import { DomainEvent } from '../events/domain-event.interface';
import { TransferOrderCreatedEvent } from '../events/transfer-order-created.event';
import { TransferStatusChangedEvent } from '../events/transfer-status-changed.event';
import { TransferCompletedEvent } from '../events/transfer-completed.event';
import {
  TransferOrderStatus,
  CANCELLABLE_STATUSES,
  TERMINAL_STATUSES,
} from '../value-objects/transfer-order-status.enum';
import { SagaStep } from '../value-objects/saga-step.enum';
import { v4 as uuidv4 } from 'uuid';

export interface TransferOrderData {
  id: bigint | null;
  transferOrderNo: string;
  sellerUserId: bigint;
  sellerAccountSequence: string;
  buyerUserId: bigint;
  buyerAccountSequence: string;
  sourceOrderNo: string;
  sourceAdoptionId: bigint;
  treeCount: number;
  contributionPerTree: string;
  originalAdoptionDate: Date;
  originalExpireDate: Date;
  selectedProvince: string;
  selectedCity: string;
  transferPrice: string;
  platformFeeRate: string;
  platformFeeAmount: string;
  sellerReceiveAmount: string;
  status: string;
  sagaStep: string;
  failReason: string | null;
  retryCount: number;
  sellerConfirmedAt: Date | null;
  paymentFrozenAt: Date | null;
  treesLockedAt: Date | null;
  ownershipTransferredAt: Date | null;
  contributionAdjustedAt: Date | null;
  statsUpdatedAt: Date | null;
  paymentSettledAt: Date | null;
  completedAt: Date | null;
  cancelledAt: Date | null;
  rolledBackAt: Date | null;
  createdAt: Date;
  updatedAt: Date;
}

export interface CreateTransferOrderParams {
  sellerUserId: bigint;
  sellerAccountSequence: string;
  buyerUserId: bigint;
  buyerAccountSequence: string;
  sourceOrderNo: string;
  sourceAdoptionId: bigint;
  treeCount: number;
  contributionPerTree: string;
  originalAdoptionDate: Date;
  originalExpireDate: Date;
  selectedProvince: string;
  selectedCity: string;
  transferPrice: string;
  platformFeeRate: string;
  platformFeeAmount: string;
  sellerReceiveAmount: string;
}

export class TransferOrder {
  private _id: bigint | null;
  private readonly _transferOrderNo: string;
  private readonly _sellerUserId: bigint;
  private readonly _sellerAccountSequence: string;
  private readonly _buyerUserId: bigint;
  private readonly _buyerAccountSequence: string;
  private readonly _sourceOrderNo: string;
  private readonly _sourceAdoptionId: bigint;
  private readonly _treeCount: number;
  private readonly _contributionPerTree: string;
  private readonly _originalAdoptionDate: Date;
  private readonly _originalExpireDate: Date;
  private readonly _selectedProvince: string;
  private readonly _selectedCity: string;
  private readonly _transferPrice: string;
  private readonly _platformFeeRate: string;
  private readonly _platformFeeAmount: string;
  private readonly _sellerReceiveAmount: string;
  private _status: TransferOrderStatus;
  private _sagaStep: SagaStep;
  private _failReason: string | null;
  private _retryCount: number;
  private _sellerConfirmedAt: Date | null;
  private _paymentFrozenAt: Date | null;
  private _treesLockedAt: Date | null;
  private _ownershipTransferredAt: Date | null;
  private _contributionAdjustedAt: Date | null;
  private _statsUpdatedAt: Date | null;
  private _paymentSettledAt: Date | null;
  private _completedAt: Date | null;
  private _cancelledAt: Date | null;
  private _rolledBackAt: Date | null;
  private _createdAt: Date;
  private _updatedAt: Date;
  private _domainEvents: DomainEvent[] = [];

  private constructor(params: {
    id: bigint | null;
    transferOrderNo: string;
    sellerUserId: bigint;
    sellerAccountSequence: string;
    buyerUserId: bigint;
    buyerAccountSequence: string;
    sourceOrderNo: string;
    sourceAdoptionId: bigint;
    treeCount: number;
    contributionPerTree: string;
    originalAdoptionDate: Date;
    originalExpireDate: Date;
    selectedProvince: string;
    selectedCity: string;
    transferPrice: string;
    platformFeeRate: string;
    platformFeeAmount: string;
    sellerReceiveAmount: string;
    status: TransferOrderStatus;
    sagaStep: SagaStep;
    failReason: string | null;
    retryCount: number;
    sellerConfirmedAt: Date | null;
    paymentFrozenAt: Date | null;
    treesLockedAt: Date | null;
    ownershipTransferredAt: Date | null;
    contributionAdjustedAt: Date | null;
    statsUpdatedAt: Date | null;
    paymentSettledAt: Date | null;
    completedAt: Date | null;
    cancelledAt: Date | null;
    rolledBackAt: Date | null;
    createdAt: Date;
    updatedAt: Date;
  }) {
    this._id = params.id;
    this._transferOrderNo = params.transferOrderNo;
    this._sellerUserId = params.sellerUserId;
    this._sellerAccountSequence = params.sellerAccountSequence;
    this._buyerUserId = params.buyerUserId;
    this._buyerAccountSequence = params.buyerAccountSequence;
    this._sourceOrderNo = params.sourceOrderNo;
    this._sourceAdoptionId = params.sourceAdoptionId;
    this._treeCount = params.treeCount;
    this._contributionPerTree = params.contributionPerTree;
    this._originalAdoptionDate = params.originalAdoptionDate;
    this._originalExpireDate = params.originalExpireDate;
    this._selectedProvince = params.selectedProvince;
    this._selectedCity = params.selectedCity;
    this._transferPrice = params.transferPrice;
    this._platformFeeRate = params.platformFeeRate;
    this._platformFeeAmount = params.platformFeeAmount;
    this._sellerReceiveAmount = params.sellerReceiveAmount;
    this._status = params.status;
    this._sagaStep = params.sagaStep;
    this._failReason = params.failReason;
    this._retryCount = params.retryCount;
    this._sellerConfirmedAt = params.sellerConfirmedAt;
    this._paymentFrozenAt = params.paymentFrozenAt;
    this._treesLockedAt = params.treesLockedAt;
    this._ownershipTransferredAt = params.ownershipTransferredAt;
    this._contributionAdjustedAt = params.contributionAdjustedAt;
    this._statsUpdatedAt = params.statsUpdatedAt;
    this._paymentSettledAt = params.paymentSettledAt;
    this._completedAt = params.completedAt;
    this._cancelledAt = params.cancelledAt;
    this._rolledBackAt = params.rolledBackAt;
    this._createdAt = params.createdAt;
    this._updatedAt = params.updatedAt;
  }

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

  /**
   * 生成转让单号：TRF + YYMMDD + 8位随机字符
   */
  private static generateTransferOrderNo(): string {
    const now = new Date();
    const yy = String(now.getFullYear()).slice(2);
    const mm = String(now.getMonth() + 1).padStart(2, '0');
    const dd = String(now.getDate()).padStart(2, '0');
    const random = uuidv4().replace(/-/g, '').substring(0, 8).toUpperCase();
    return `TRF${yy}${mm}${dd}${random}`;
  }

  /**
   * 创建新的转让订单
   */
  static create(params: CreateTransferOrderParams): TransferOrder {
    const now = new Date();
    const transferOrderNo = TransferOrder.generateTransferOrderNo();

    const order = new TransferOrder({
      id: null,
      transferOrderNo,
      sellerUserId: params.sellerUserId,
      sellerAccountSequence: params.sellerAccountSequence,
      buyerUserId: params.buyerUserId,
      buyerAccountSequence: params.buyerAccountSequence,
      sourceOrderNo: params.sourceOrderNo,
      sourceAdoptionId: params.sourceAdoptionId,
      treeCount: params.treeCount,
      contributionPerTree: params.contributionPerTree,
      originalAdoptionDate: params.originalAdoptionDate,
      originalExpireDate: params.originalExpireDate,
      selectedProvince: params.selectedProvince,
      selectedCity: params.selectedCity,
      transferPrice: params.transferPrice,
      platformFeeRate: params.platformFeeRate,
      platformFeeAmount: params.platformFeeAmount,
      sellerReceiveAmount: params.sellerReceiveAmount,
      status: TransferOrderStatus.PENDING,
      sagaStep: SagaStep.INIT,
      failReason: null,
      retryCount: 0,
      sellerConfirmedAt: null,
      paymentFrozenAt: null,
      treesLockedAt: null,
      ownershipTransferredAt: null,
      contributionAdjustedAt: null,
      statsUpdatedAt: null,
      paymentSettledAt: null,
      completedAt: null,
      cancelledAt: null,
      rolledBackAt: null,
      createdAt: now,
      updatedAt: now,
    });

    order._domainEvents.push(
      new TransferOrderCreatedEvent(transferOrderNo, {
        transferOrderNo,
        sellerUserId: params.sellerUserId.toString(),
        sellerAccountSequence: params.sellerAccountSequence,
        buyerUserId: params.buyerUserId.toString(),
        buyerAccountSequence: params.buyerAccountSequence,
        sourceOrderNo: params.sourceOrderNo,
        treeCount: params.treeCount,
        transferPrice: params.transferPrice,
      }),
    );

    return order;
  }

  /**
   * 从数据库重建聚合根（不产生事件）
   */
  static reconstitute(data: TransferOrderData): TransferOrder {
    return new TransferOrder({
      id: data.id,
      transferOrderNo: data.transferOrderNo,
      sellerUserId: data.sellerUserId,
      sellerAccountSequence: data.sellerAccountSequence,
      buyerUserId: data.buyerUserId,
      buyerAccountSequence: data.buyerAccountSequence,
      sourceOrderNo: data.sourceOrderNo,
      sourceAdoptionId: data.sourceAdoptionId,
      treeCount: data.treeCount,
      contributionPerTree: data.contributionPerTree,
      originalAdoptionDate: data.originalAdoptionDate,
      originalExpireDate: data.originalExpireDate,
      selectedProvince: data.selectedProvince,
      selectedCity: data.selectedCity,
      transferPrice: data.transferPrice,
      platformFeeRate: data.platformFeeRate,
      platformFeeAmount: data.platformFeeAmount,
      sellerReceiveAmount: data.sellerReceiveAmount,
      status: data.status as TransferOrderStatus,
      sagaStep: data.sagaStep as SagaStep,
      failReason: data.failReason,
      retryCount: data.retryCount,
      sellerConfirmedAt: data.sellerConfirmedAt,
      paymentFrozenAt: data.paymentFrozenAt,
      treesLockedAt: data.treesLockedAt,
      ownershipTransferredAt: data.ownershipTransferredAt,
      contributionAdjustedAt: data.contributionAdjustedAt,
      statsUpdatedAt: data.statsUpdatedAt,
      paymentSettledAt: data.paymentSettledAt,
      completedAt: data.completedAt,
      cancelledAt: data.cancelledAt,
      rolledBackAt: data.rolledBackAt,
      createdAt: data.createdAt,
      updatedAt: data.updatedAt,
    });
  }

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

  /**
   * 卖方确认转让
   */
  sellerConfirm(): void {
    this.assertStatus(TransferOrderStatus.PENDING, '卖方确认');
    const prev = this.captureState();

    this._status = TransferOrderStatus.SELLER_CONFIRMED;
    this._sagaStep = SagaStep.FREEZE_BUYER_PAYMENT;
    this._sellerConfirmedAt = new Date();

    this.pushStatusChangedEvent(prev);
  }

  /**
   * 买方资金冻结完成
   */
  markPaymentFrozen(): void {
    this.assertStatus(TransferOrderStatus.SELLER_CONFIRMED, '冻结资金');
    const prev = this.captureState();

    this._status = TransferOrderStatus.PAYMENT_FROZEN;
    this._sagaStep = SagaStep.LOCK_SELLER_TREES;
    this._paymentFrozenAt = new Date();

    this.pushStatusChangedEvent(prev);
  }

  /**
   * 卖方树锁定完成
   */
  markTreesLocked(): void {
    this.assertStatus(TransferOrderStatus.PAYMENT_FROZEN, '锁定树');
    const prev = this.captureState();

    this._status = TransferOrderStatus.TREES_LOCKED;
    this._sagaStep = SagaStep.TRANSFER_OWNERSHIP;
    this._treesLockedAt = new Date();

    this.pushStatusChangedEvent(prev);
  }

  /**
   * 所有权变更完成
   */
  markOwnershipTransferred(): void {
    this.assertStatus(TransferOrderStatus.TREES_LOCKED, '所有权变更');
    const prev = this.captureState();

    this._status = TransferOrderStatus.OWNERSHIP_TRANSFERRED;
    this._sagaStep = SagaStep.ADJUST_CONTRIBUTION;
    this._ownershipTransferredAt = new Date();

    this.pushStatusChangedEvent(prev);
  }

  /**
   * 算力调整完成
   */
  markContributionAdjusted(): void {
    this.assertStatus(TransferOrderStatus.OWNERSHIP_TRANSFERRED, '算力调整');
    const prev = this.captureState();

    this._status = TransferOrderStatus.CONTRIBUTION_ADJUSTED;
    this._sagaStep = SagaStep.UPDATE_TEAM_STATS;
    this._contributionAdjustedAt = new Date();

    this.pushStatusChangedEvent(prev);
  }

  /**
   * 团队统计更新完成
   */
  markStatsUpdated(): void {
    this.assertStatus(TransferOrderStatus.CONTRIBUTION_ADJUSTED, '团队统计更新');
    const prev = this.captureState();

    this._status = TransferOrderStatus.STATS_UPDATED;
    this._sagaStep = SagaStep.SETTLE_PAYMENT;
    this._statsUpdatedAt = new Date();

    this.pushStatusChangedEvent(prev);
  }

  /**
   * 资金结算完成
   */
  markPaymentSettled(): void {
    this.assertStatus(TransferOrderStatus.STATS_UPDATED, '资金结算');
    const prev = this.captureState();

    this._status = TransferOrderStatus.PAYMENT_SETTLED;
    this._sagaStep = SagaStep.FINALIZE;
    this._paymentSettledAt = new Date();

    this.pushStatusChangedEvent(prev);
  }

  /**
   * 转让完成
   */
  complete(): void {
    this.assertStatus(TransferOrderStatus.PAYMENT_SETTLED, '完成');
    const prev = this.captureState();

    this._status = TransferOrderStatus.COMPLETED;
    this._sagaStep = SagaStep.FINALIZE;
    this._completedAt = new Date();

    this.pushStatusChangedEvent(prev);

    this._domainEvents.push(
      new TransferCompletedEvent(this._transferOrderNo, {
        transferOrderNo: this._transferOrderNo,
        sellerUserId: this._sellerUserId.toString(),
        sellerAccountSequence: this._sellerAccountSequence,
        buyerUserId: this._buyerUserId.toString(),
        buyerAccountSequence: this._buyerAccountSequence,
        sourceOrderNo: this._sourceOrderNo,
        treeCount: this._treeCount,
        contributionPerTree: this._contributionPerTree,
        selectedProvince: this._selectedProvince,
        selectedCity: this._selectedCity,
        originalAdoptionDate: this._originalAdoptionDate.toISOString(),
        originalExpireDate: this._originalExpireDate.toISOString(),
        transferPrice: this._transferPrice,
        completedAt: this._completedAt!.toISOString(),
      }),
    );
  }

  /**
   * 取消转让（仅限 PENDING / SELLER_CONFIRMED 阶段）
   */
  cancel(): void {
    if (!CANCELLABLE_STATUSES.includes(this._status as any)) {
      throw new Error(`当前状态 ${this._status} 不允许取消`);
    }
    const prev = this.captureState();

    this._status = TransferOrderStatus.CANCELLED;
    this._cancelledAt = new Date();

    this.pushStatusChangedEvent(prev);
  }

  /**
   * 标记为失败并开始回滚
   */
  markFailed(reason: string): void {
    if (TERMINAL_STATUSES.includes(this._status as any)) {
      throw new Error(`当前状态 ${this._status} 已是终态，不能标记为失败`);
    }
    const prev = this.captureState();

    this._failReason = reason;
    this._status = TransferOrderStatus.ROLLING_BACK;

    // 根据当前步骤确定补偿起点
    if (this._treesLockedAt) {
      this._sagaStep = SagaStep.COMPENSATE_UNLOCK_TREES;
    } else if (this._paymentFrozenAt) {
      this._sagaStep = SagaStep.COMPENSATE_UNFREEZE;
    } else {
      this._status = TransferOrderStatus.FAILED;
    }

    this.pushStatusChangedEvent(prev);
  }

  /**
   * 补偿完成（解锁树后，继续解冻资金）
   */
  advanceCompensation(): void {
    if (this._status !== TransferOrderStatus.ROLLING_BACK) {
      throw new Error(`当前状态 ${this._status} 不在回滚中`);
    }
    const prev = this.captureState();

    if (this._sagaStep === SagaStep.COMPENSATE_UNLOCK_TREES && this._paymentFrozenAt) {
      this._sagaStep = SagaStep.COMPENSATE_UNFREEZE;
    } else {
      this._status = TransferOrderStatus.ROLLED_BACK;
      this._rolledBackAt = new Date();
    }

    this.pushStatusChangedEvent(prev);
  }

  /**
   * 标记回滚完成
   */
  markRolledBack(): void {
    const prev = this.captureState();
    this._status = TransferOrderStatus.ROLLED_BACK;
    this._rolledBackAt = new Date();
    this.pushStatusChangedEvent(prev);
  }

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

  get id(): bigint | null { return this._id; }
  get transferOrderNo(): string { return this._transferOrderNo; }
  get sellerUserId(): bigint { return this._sellerUserId; }
  get sellerAccountSequence(): string { return this._sellerAccountSequence; }
  get buyerUserId(): bigint { return this._buyerUserId; }
  get buyerAccountSequence(): string { return this._buyerAccountSequence; }
  get sourceOrderNo(): string { return this._sourceOrderNo; }
  get sourceAdoptionId(): bigint { return this._sourceAdoptionId; }
  get treeCount(): number { return this._treeCount; }
  get contributionPerTree(): string { return this._contributionPerTree; }
  get originalAdoptionDate(): Date { return this._originalAdoptionDate; }
  get originalExpireDate(): Date { return this._originalExpireDate; }
  get selectedProvince(): string { return this._selectedProvince; }
  get selectedCity(): string { return this._selectedCity; }
  get transferPrice(): string { return this._transferPrice; }
  get platformFeeRate(): string { return this._platformFeeRate; }
  get platformFeeAmount(): string { return this._platformFeeAmount; }
  get sellerReceiveAmount(): string { return this._sellerReceiveAmount; }
  get status(): TransferOrderStatus { return this._status; }
  get sagaStep(): SagaStep { return this._sagaStep; }
  get failReason(): string | null { return this._failReason; }
  get retryCount(): number { return this._retryCount; }
  get sellerConfirmedAt(): Date | null { return this._sellerConfirmedAt; }
  get paymentFrozenAt(): Date | null { return this._paymentFrozenAt; }
  get treesLockedAt(): Date | null { return this._treesLockedAt; }
  get ownershipTransferredAt(): Date | null { return this._ownershipTransferredAt; }
  get contributionAdjustedAt(): Date | null { return this._contributionAdjustedAt; }
  get statsUpdatedAt(): Date | null { return this._statsUpdatedAt; }
  get paymentSettledAt(): Date | null { return this._paymentSettledAt; }
  get completedAt(): Date | null { return this._completedAt; }
  get cancelledAt(): Date | null { return this._cancelledAt; }
  get rolledBackAt(): Date | null { return this._rolledBackAt; }
  get createdAt(): Date { return this._createdAt; }

  // ========== 事件管理 ==========

  getDomainEvents(): readonly DomainEvent[] {
    return this._domainEvents;
  }

  clearDomainEvents(): void {
    this._domainEvents = [];
  }

  setId(id: bigint): void {
    this._id = id;
  }

  // ========== 持久化 ==========

  toPersistence(): Omit<TransferOrderData, 'updatedAt'> {
    return {
      id: this._id,
      transferOrderNo: this._transferOrderNo,
      sellerUserId: this._sellerUserId,
      sellerAccountSequence: this._sellerAccountSequence,
      buyerUserId: this._buyerUserId,
      buyerAccountSequence: this._buyerAccountSequence,
      sourceOrderNo: this._sourceOrderNo,
      sourceAdoptionId: this._sourceAdoptionId,
      treeCount: this._treeCount,
      contributionPerTree: this._contributionPerTree,
      originalAdoptionDate: this._originalAdoptionDate,
      originalExpireDate: this._originalExpireDate,
      selectedProvince: this._selectedProvince,
      selectedCity: this._selectedCity,
      transferPrice: this._transferPrice,
      platformFeeRate: this._platformFeeRate,
      platformFeeAmount: this._platformFeeAmount,
      sellerReceiveAmount: this._sellerReceiveAmount,
      status: this._status,
      sagaStep: this._sagaStep,
      failReason: this._failReason,
      retryCount: this._retryCount,
      sellerConfirmedAt: this._sellerConfirmedAt,
      paymentFrozenAt: this._paymentFrozenAt,
      treesLockedAt: this._treesLockedAt,
      ownershipTransferredAt: this._ownershipTransferredAt,
      contributionAdjustedAt: this._contributionAdjustedAt,
      statsUpdatedAt: this._statsUpdatedAt,
      paymentSettledAt: this._paymentSettledAt,
      completedAt: this._completedAt,
      cancelledAt: this._cancelledAt,
      rolledBackAt: this._rolledBackAt,
      createdAt: this._createdAt,
    };
  }

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

  private assertStatus(expected: TransferOrderStatus, operation: string): void {
    if (this._status !== expected) {
      throw new Error(`操作"${operation}"要求状态为 ${expected}，当前状态为 ${this._status}`);
    }
  }

  private captureState(): { status: string; sagaStep: string } {
    return { status: this._status, sagaStep: this._sagaStep };
  }

  private pushStatusChangedEvent(prev: { status: string; sagaStep: string }): void {
    this._domainEvents.push(
      new TransferStatusChangedEvent(this._transferOrderNo, {
        transferOrderNo: this._transferOrderNo,
        fromStatus: prev.status,
        toStatus: this._status,
        fromSagaStep: prev.sagaStep,
        toSagaStep: this._sagaStep,
      }),
    );
  }
}
