import Decimal from 'decimal.js';
import { UserId, ChainType, DepositStatus, Money } from '@/domain/value-objects';
import { DomainError } from '@/shared/exceptions/domain.exception';

export class DepositOrder {
  private readonly _id: bigint;
  private readonly _accountSequence: string;  // 跨服务关联标识 (全局唯一业务ID)
  private readonly _userId: UserId;           // 保留兼容
  private readonly _chainType: ChainType;
  private readonly _amount: Money;
  private readonly _txHash: string;
  private _status: DepositStatus;
  private _confirmedAt: Date | null;
  private readonly _createdAt: Date;

  private constructor(
    id: bigint,
    accountSequence: string,
    userId: UserId,
    chainType: ChainType,
    amount: Money,
    txHash: string,
    status: DepositStatus,
    confirmedAt: Date | null,
    createdAt: Date,
  ) {
    this._id = id;
    this._accountSequence = accountSequence;
    this._userId = userId;
    this._chainType = chainType;
    this._amount = amount;
    this._txHash = txHash;
    this._status = status;
    this._confirmedAt = confirmedAt;
    this._createdAt = createdAt;
  }

  // Getters
  get id(): bigint { return this._id; }
  get accountSequence(): string { return this._accountSequence; }
  get userId(): UserId { return this._userId; }
  get chainType(): ChainType { return this._chainType; }
  get amount(): Money { return this._amount; }
  get txHash(): string { return this._txHash; }
  get status(): DepositStatus { return this._status; }
  get confirmedAt(): Date | null { return this._confirmedAt; }
  get createdAt(): Date { return this._createdAt; }
  get isPending(): boolean { return this._status === DepositStatus.PENDING; }
  get isConfirmed(): boolean { return this._status === DepositStatus.CONFIRMED; }

  static create(params: {
    accountSequence: string;
    userId: UserId;
    chainType: ChainType;
    amount: Money;
    txHash: string;
  }): DepositOrder {
    return new DepositOrder(
      BigInt(0), // Will be set by database
      params.accountSequence,
      params.userId,
      params.chainType,
      params.amount,
      params.txHash,
      DepositStatus.PENDING,
      null,
      new Date(),
    );
  }

  static reconstruct(params: {
    id: bigint;
    accountSequence: string;
    userId: bigint;
    chainType: string;
    amount: Decimal;
    txHash: string;
    status: string;
    confirmedAt: Date | null;
    createdAt: Date;
  }): DepositOrder {
    return new DepositOrder(
      params.id,
      params.accountSequence,
      UserId.create(params.userId),
      params.chainType as ChainType,
      Money.USDT(params.amount),
      params.txHash,
      params.status as DepositStatus,
      params.confirmedAt,
      params.createdAt,
    );
  }

  confirm(): void {
    if (this._status !== DepositStatus.PENDING) {
      throw new DomainError('Only pending deposits can be confirmed');
    }
    this._status = DepositStatus.CONFIRMED;
    this._confirmedAt = new Date();
  }

  fail(): void {
    if (this._status !== DepositStatus.PENDING) {
      throw new DomainError('Only pending deposits can be marked as failed');
    }
    this._status = DepositStatus.FAILED;
  }
}
