/**
 * 合同签署任务聚合根
 *
 * 独立模块，不影响现有认种流程
 * 通过订阅 OrderPaid 事件创建签署任务
 */

import { ContractSigningStatus } from '../value-objects/contract-signing-status.enum';

/**
 * 设备信息
 */
export interface DeviceInfo {
  deviceId?: string;
  deviceModel?: string;
  osVersion?: string;
  appVersion?: string;
}

/**
 * 签署位置信息
 */
export interface SigningLocation {
  latitude?: number;
  longitude?: number;
}

/**
 * 创建合同签署任务的参数
 */
export interface CreateContractSigningTaskParams {
  orderNo: string;
  userId: bigint;
  accountSequence: string;
  templateId: number;
  contractVersion: string;
  contractContent: string;
  userPhoneNumber?: string;
  userRealName?: string;
  userIdCardNumber?: string;
  treeCount: number;
  totalAmount: number;
  provinceCode: string;
  provinceName: string;
  cityCode: string;
  cityName: string;
  expiresAt: Date;
}

/**
 * 签署合同的参数
 */
export interface SignContractParams {
  signatureCloudUrl: string;
  signatureHash: string;
  signedPdfUrl: string;
  ipAddress: string;
  deviceInfo: DeviceInfo;
  userAgent: string;
  location?: SigningLocation;
  signatureTrace?: string; // JSON 格式的签名轨迹数据（时间戳、笔画顺序）
}

export class ContractSigningTask {
  private _id?: bigint;
  private _orderNo: string;
  private _contractNo: string;
  private _userId: bigint;
  private _accountSequence: string;
  private _templateId: number;
  private _contractVersion: string;
  private _contractContent: string;
  private _userPhoneNumber?: string;
  private _userRealName?: string;
  private _userIdCardNumber?: string;
  private _treeCount: number;
  private _totalAmount: number;
  private _provinceCode: string;
  private _provinceName: string;
  private _cityCode: string;
  private _cityName: string;
  private _status: ContractSigningStatus;
  private _expiresAt: Date;
  private _scrolledToBottomAt?: Date;
  private _acknowledgedAt?: Date;
  private _signedAt?: Date;
  private _signatureCloudUrl?: string;
  private _signatureHash?: string;
  private _signedPdfUrl?: string;
  private _signingIpAddress?: string;
  private _signingDeviceInfo?: DeviceInfo;
  private _signingUserAgent?: string;
  private _signingLatitude?: number;
  private _signingLongitude?: number;
  private _createdAt: Date;
  private _updatedAt: Date;

  private constructor() {
    this._createdAt = new Date();
    this._updatedAt = new Date();
  }

  // ============================================
  // 工厂方法
  // ============================================

  /**
   * 创建新的合同签署任务
   */
  static create(params: CreateContractSigningTaskParams): ContractSigningTask {
    const task = new ContractSigningTask();
    task._orderNo = params.orderNo;
    // 生成合同编号: accountSequence-yyyyMMddHHmm
    task._contractNo = ContractSigningTask.generateContractNo(params.accountSequence);
    task._userId = params.userId;
    task._accountSequence = params.accountSequence;
    task._templateId = params.templateId;
    task._contractVersion = params.contractVersion;
    task._contractContent = params.contractContent;
    task._userPhoneNumber = params.userPhoneNumber;
    task._userRealName = params.userRealName;
    task._userIdCardNumber = params.userIdCardNumber;
    task._treeCount = params.treeCount;
    task._totalAmount = params.totalAmount;
    task._provinceCode = params.provinceCode;
    task._provinceName = params.provinceName;
    task._cityCode = params.cityCode;
    task._cityName = params.cityName;
    task._status = ContractSigningStatus.PENDING;
    task._expiresAt = params.expiresAt;
    return task;
  }

  /**
   * 从持久化数据重建
   */
  static reconstitute(data: {
    id: bigint;
    orderNo: string;
    contractNo: string;
    userId: bigint;
    accountSequence: string;
    templateId: number;
    contractVersion: string;
    contractContent: string;
    userPhoneNumber?: string;
    userRealName?: string;
    userIdCardNumber?: string;
    treeCount: number;
    totalAmount: number;
    provinceCode: string;
    provinceName: string;
    cityCode: string;
    cityName: string;
    status: string;
    expiresAt: Date;
    scrolledToBottomAt?: Date;
    acknowledgedAt?: Date;
    signedAt?: Date;
    signatureCloudUrl?: string;
    signatureHash?: string;
    signedPdfUrl?: string;
    signingIpAddress?: string;
    signingDeviceInfo?: DeviceInfo;
    signingUserAgent?: string;
    signingLatitude?: number;
    signingLongitude?: number;
    createdAt: Date;
    updatedAt: Date;
  }): ContractSigningTask {
    const task = new ContractSigningTask();
    task._id = data.id;
    task._orderNo = data.orderNo;
    task._contractNo = data.contractNo;
    task._userId = data.userId;
    task._accountSequence = data.accountSequence;
    task._templateId = data.templateId;
    task._contractVersion = data.contractVersion;
    task._contractContent = data.contractContent;
    task._userPhoneNumber = data.userPhoneNumber;
    task._userRealName = data.userRealName;
    task._userIdCardNumber = data.userIdCardNumber;
    task._treeCount = data.treeCount;
    task._totalAmount = data.totalAmount;
    task._provinceCode = data.provinceCode;
    task._provinceName = data.provinceName;
    task._cityCode = data.cityCode;
    task._cityName = data.cityName;
    task._status = data.status as ContractSigningStatus;
    task._expiresAt = data.expiresAt;
    task._scrolledToBottomAt = data.scrolledToBottomAt;
    task._acknowledgedAt = data.acknowledgedAt;
    task._signedAt = data.signedAt;
    task._signatureCloudUrl = data.signatureCloudUrl;
    task._signatureHash = data.signatureHash;
    task._signedPdfUrl = data.signedPdfUrl;
    task._signingIpAddress = data.signingIpAddress;
    task._signingDeviceInfo = data.signingDeviceInfo;
    task._signingUserAgent = data.signingUserAgent;
    task._signingLatitude = data.signingLatitude;
    task._signingLongitude = data.signingLongitude;
    task._createdAt = data.createdAt;
    task._updatedAt = data.updatedAt;
    return task;
  }

  // ============================================
  // Getters
  // ============================================

  get id(): bigint | undefined {
    return this._id;
  }

  get orderNo(): string {
    return this._orderNo;
  }

  get contractNo(): string {
    return this._contractNo;
  }

  get userId(): bigint {
    return this._userId;
  }

  get accountSequence(): string {
    return this._accountSequence;
  }

  get templateId(): number {
    return this._templateId;
  }

  get contractVersion(): string {
    return this._contractVersion;
  }

  get contractContent(): string {
    return this._contractContent;
  }

  get userPhoneNumber(): string | undefined {
    return this._userPhoneNumber;
  }

  get userRealName(): string | undefined {
    return this._userRealName;
  }

  get userIdCardNumber(): string | undefined {
    return this._userIdCardNumber;
  }

  get treeCount(): number {
    return this._treeCount;
  }

  get totalAmount(): number {
    return this._totalAmount;
  }

  get provinceCode(): string {
    return this._provinceCode;
  }

  get provinceName(): string {
    return this._provinceName;
  }

  get cityCode(): string {
    return this._cityCode;
  }

  get cityName(): string {
    return this._cityName;
  }

  get status(): ContractSigningStatus {
    return this._status;
  }

  get expiresAt(): Date {
    return this._expiresAt;
  }

  get scrolledToBottomAt(): Date | undefined {
    return this._scrolledToBottomAt;
  }

  get acknowledgedAt(): Date | undefined {
    return this._acknowledgedAt;
  }

  get signedAt(): Date | undefined {
    return this._signedAt;
  }

  get signatureCloudUrl(): string | undefined {
    return this._signatureCloudUrl;
  }

  get signatureHash(): string | undefined {
    return this._signatureHash;
  }

  get signedPdfUrl(): string | undefined {
    return this._signedPdfUrl;
  }

  get signingIpAddress(): string | undefined {
    return this._signingIpAddress;
  }

  get signingDeviceInfo(): DeviceInfo | undefined {
    return this._signingDeviceInfo;
  }

  get signingUserAgent(): string | undefined {
    return this._signingUserAgent;
  }

  get signingLatitude(): number | undefined {
    return this._signingLatitude;
  }

  get signingLongitude(): number | undefined {
    return this._signingLongitude;
  }

  get createdAt(): Date {
    return this._createdAt;
  }

  get updatedAt(): Date {
    return this._updatedAt;
  }

  // ============================================
  // 业务方法
  // ============================================

  /**
   * 检查是否已过期
   */
  isExpired(): boolean {
    return new Date() > this._expiresAt;
  }

  /**
   * 检查是否可以继续签署流程
   */
  canContinueSigning(): boolean {
    return (
      !this.isExpired() &&
      this._status !== ContractSigningStatus.SIGNED &&
      this._status !== ContractSigningStatus.UNSIGNED_TIMEOUT
    );
  }

  /**
   * 标记已滚动到底部
   */
  markScrolledToBottom(): void {
    if (!this.canContinueSigning()) {
      throw new Error('无法继续签署流程：任务已过期或已完成');
    }

    if (this._status === ContractSigningStatus.PENDING) {
      this._status = ContractSigningStatus.SCROLLED;
      this._scrolledToBottomAt = new Date();
      this._updatedAt = new Date();
    }
  }

  /**
   * 确认法律效力
   */
  acknowledge(): void {
    if (!this.canContinueSigning()) {
      throw new Error('无法继续签署流程：任务已过期或已完成');
    }

    if (
      this._status !== ContractSigningStatus.SCROLLED &&
      this._status !== ContractSigningStatus.PENDING
    ) {
      throw new Error('请先滚动到合同底部');
    }

    this._status = ContractSigningStatus.ACKNOWLEDGED;
    this._acknowledgedAt = new Date();
    this._updatedAt = new Date();
  }

  /**
   * 完成签署
   */
  sign(params: SignContractParams): void {
    if (!this.canContinueSigning()) {
      throw new Error('无法继续签署流程：任务已过期或已完成');
    }

    if (this._status !== ContractSigningStatus.ACKNOWLEDGED) {
      throw new Error('请先确认法律效力');
    }

    this._status = ContractSigningStatus.SIGNED;
    this._signedAt = new Date();
    this._signatureCloudUrl = params.signatureCloudUrl;
    this._signatureHash = params.signatureHash;
    this._signedPdfUrl = params.signedPdfUrl;
    this._signingIpAddress = params.ipAddress;
    this._signingDeviceInfo = params.deviceInfo;
    this._signingUserAgent = params.userAgent;
    if (params.location) {
      this._signingLatitude = params.location.latitude;
      this._signingLongitude = params.location.longitude;
    }
    this._updatedAt = new Date();
  }

  /**
   * 标记为超时未签署
   */
  markAsTimeout(): void {
    if (
      this._status === ContractSigningStatus.SIGNED ||
      this._status === ContractSigningStatus.UNSIGNED_TIMEOUT
    ) {
      return; // 已完成或已超时，不做处理
    }

    this._status = ContractSigningStatus.UNSIGNED_TIMEOUT;
    this._updatedAt = new Date();
  }

  /**
   * 补签合同（超时后用户仍可补签）
   */
  lateSign(params: SignContractParams): void {
    if (this._status === ContractSigningStatus.SIGNED) {
      throw new Error('合同已签署');
    }

    this._status = ContractSigningStatus.SIGNED;
    this._signedAt = new Date();
    this._signatureCloudUrl = params.signatureCloudUrl;
    this._signatureHash = params.signatureHash;
    this._signedPdfUrl = params.signedPdfUrl;
    this._signingIpAddress = params.ipAddress;
    this._signingDeviceInfo = params.deviceInfo;
    this._signingUserAgent = params.userAgent;
    if (params.location) {
      this._signingLatitude = params.location.latitude;
      this._signingLongitude = params.location.longitude;
    }
    this._updatedAt = new Date();
  }

  // ============================================
  // 私有辅助方法
  // ============================================

  /**
   * 生成合同编号
   * 格式: accountSequence-yyyyMMddHHmm
   */
  private static generateContractNo(accountSequence: string): string {
    const now = new Date();
    const year = now.getFullYear();
    const month = String(now.getMonth() + 1).padStart(2, '0');
    const day = String(now.getDate()).padStart(2, '0');
    const hour = String(now.getHours()).padStart(2, '0');
    const minute = String(now.getMinutes()).padStart(2, '0');
    return `${accountSequence}-${year}${month}${day}${hour}${minute}`;
  }
}
