import { AggregateRoot } from '../aggregate-root.base';
import { DepositDetectedEvent, DepositConfirmedEvent } from '@/domain/events';
import { ChainType, TxHash, EvmAddress, TokenAmount, BlockNumber } from '@/domain/value-objects';
import { DepositStatus } from '@/domain/enums';

export interface DepositTransactionProps {
  id?: bigint;
  chainType: ChainType;
  txHash: TxHash;
  fromAddress: EvmAddress;
  toAddress: EvmAddress;
  tokenContract: EvmAddress;
  amount: TokenAmount;
  blockNumber: BlockNumber;
  blockTimestamp: Date;
  logIndex: number;
  confirmations: number;
  status: DepositStatus;
  addressId: bigint;
  accountSequence: string; // 跨服务关联标识 (格式: D + YYMMDD + 5位序号)
  userId: bigint; // 保留兼容
  notifiedAt?: Date;
  notifyAttempts: number;
  lastNotifyError?: string;
  createdAt?: Date;
  updatedAt?: Date;
}

export class DepositTransaction extends AggregateRoot<bigint> {
  private props: DepositTransactionProps;

  private constructor(props: DepositTransactionProps) {
    super();
    this.props = props;
  }

  // Getters
  get id(): bigint | undefined {
    return this.props.id;
  }
  get chainType(): ChainType {
    return this.props.chainType;
  }
  get txHash(): TxHash {
    return this.props.txHash;
  }
  get fromAddress(): EvmAddress {
    return this.props.fromAddress;
  }
  get toAddress(): EvmAddress {
    return this.props.toAddress;
  }
  get tokenContract(): EvmAddress {
    return this.props.tokenContract;
  }
  get amount(): TokenAmount {
    return this.props.amount;
  }
  get blockNumber(): BlockNumber {
    return this.props.blockNumber;
  }
  get blockTimestamp(): Date {
    return this.props.blockTimestamp;
  }
  get logIndex(): number {
    return this.props.logIndex;
  }
  get confirmations(): number {
    return this.props.confirmations;
  }
  get status(): DepositStatus {
    return this.props.status;
  }
  get addressId(): bigint {
    return this.props.addressId;
  }
  get accountSequence(): string {
    return this.props.accountSequence;
  }
  get userId(): bigint {
    return this.props.userId;
  }
  get notifiedAt(): Date | undefined {
    return this.props.notifiedAt;
  }
  get notifyAttempts(): number {
    return this.props.notifyAttempts;
  }
  get lastNotifyError(): string | undefined {
    return this.props.lastNotifyError;
  }
  get createdAt(): Date | undefined {
    return this.props.createdAt;
  }
  get updatedAt(): Date | undefined {
    return this.props.updatedAt;
  }

  get isConfirmed(): boolean {
    return this.props.status === DepositStatus.CONFIRMED;
  }
  get isNotified(): boolean {
    return this.props.status === DepositStatus.NOTIFIED;
  }

  /**
   * 创建新的充值交易（检测到时）
   */
  static create(params: {
    chainType: ChainType;
    txHash: TxHash;
    fromAddress: EvmAddress;
    toAddress: EvmAddress;
    tokenContract: EvmAddress;
    amount: TokenAmount;
    blockNumber: BlockNumber;
    blockTimestamp: Date;
    logIndex: number;
    addressId: bigint;
    accountSequence: string;
    userId: bigint;
  }): DepositTransaction {
    const deposit = new DepositTransaction({
      ...params,
      confirmations: 0,
      status: DepositStatus.DETECTED,
      notifyAttempts: 0,
    });

    deposit.addDomainEvent(
      new DepositDetectedEvent({
        depositId: '0', // Will be set after persistence
        chainType: params.chainType.toString(),
        txHash: params.txHash.toString(),
        fromAddress: params.fromAddress.toString(),
        toAddress: params.toAddress.toString(),
        tokenContract: params.tokenContract.toString(),
        amount: params.amount.raw.toString(),
        amountFormatted: params.amount.toFixed(8),
        blockNumber: params.blockNumber.toString(),
        blockTimestamp: params.blockTimestamp.toISOString(),
        accountSequence: params.accountSequence,
        userId: params.userId.toString(),
      }),
    );

    return deposit;
  }

  /**
   * 从持久化数据重建
   */
  static reconstitute(props: DepositTransactionProps): DepositTransaction {
    return new DepositTransaction(props);
  }

  /**
   * 更新确认数
   */
  updateConfirmations(currentBlockNumber: BlockNumber, requiredConfirmations: number): void {
    const confirmations = Number(currentBlockNumber.diff(this.props.blockNumber));
    this.props.confirmations = Math.max(0, confirmations);

    // 检查是否达到确认要求（状态为 DETECTED 或 CONFIRMING 都可以确认）
    if (
      this.props.confirmations >= requiredConfirmations &&
      (this.props.status === DepositStatus.DETECTED || this.props.status === DepositStatus.CONFIRMING)
    ) {
      this.confirm();
    } else if (this.props.status === DepositStatus.DETECTED) {
      // 首次检测但确认数不够，标记为确认中
      this.props.status = DepositStatus.CONFIRMING;
    }
  }

  /**
   * 确认充值
   */
  private confirm(): void {
    this.props.status = DepositStatus.CONFIRMED;

    this.addDomainEvent(
      new DepositConfirmedEvent({
        depositId: this.props.id?.toString() ?? '0',
        chainType: this.props.chainType.toString(),
        txHash: this.props.txHash.toString(),
        toAddress: this.props.toAddress.toString(),
        amount: this.props.amount.raw.toString(),
        amountFormatted: this.props.amount.toFixed(8),
        confirmations: this.props.confirmations,
        accountSequence: this.props.accountSequence,
        userId: this.props.userId.toString(),
      }),
    );
  }

  /**
   * 标记为已通知
   */
  markAsNotified(): void {
    this.props.status = DepositStatus.NOTIFIED;
    this.props.notifiedAt = new Date();
  }

  /**
   * 记录通知失败
   */
  recordNotifyFailure(error: string): void {
    this.props.notifyAttempts += 1;
    this.props.lastNotifyError = error;
  }
}
