import { AggregateRoot } from '../aggregate-root.base';
import { TransactionBroadcastedEvent } from '@/domain/events';
import { ChainType, TxHash, EvmAddress, TokenAmount } from '@/domain/value-objects';
import { TransactionStatus } from '@/domain/enums';
import { Decimal } from '@prisma/client/runtime/library';

export interface TransactionRequestProps {
  id?: bigint;
  chainType: ChainType;
  sourceService: string;
  sourceOrderId: string;
  fromAddress: EvmAddress;
  toAddress: EvmAddress;
  value: TokenAmount;
  data?: string;
  signedTx?: string;
  txHash?: TxHash;
  status: TransactionStatus;
  gasLimit?: bigint;
  gasPrice?: Decimal;
  nonce?: number;
  errorMessage?: string;
  retryCount: number;
  createdAt?: Date;
  updatedAt?: Date;
}

export class TransactionRequest extends AggregateRoot<bigint> {
  private props: TransactionRequestProps;

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

  // Getters
  get id(): bigint | undefined {
    return this.props.id;
  }
  get chainType(): ChainType {
    return this.props.chainType;
  }
  get sourceService(): string {
    return this.props.sourceService;
  }
  get sourceOrderId(): string {
    return this.props.sourceOrderId;
  }
  get fromAddress(): EvmAddress {
    return this.props.fromAddress;
  }
  get toAddress(): EvmAddress {
    return this.props.toAddress;
  }
  get value(): TokenAmount {
    return this.props.value;
  }
  get data(): string | undefined {
    return this.props.data;
  }
  get signedTx(): string | undefined {
    return this.props.signedTx;
  }
  get txHash(): TxHash | undefined {
    return this.props.txHash;
  }
  get status(): TransactionStatus {
    return this.props.status;
  }
  get gasLimit(): bigint | undefined {
    return this.props.gasLimit;
  }
  get gasPrice(): Decimal | undefined {
    return this.props.gasPrice;
  }
  get nonce(): number | undefined {
    return this.props.nonce;
  }
  get errorMessage(): string | undefined {
    return this.props.errorMessage;
  }
  get retryCount(): number {
    return this.props.retryCount;
  }
  get createdAt(): Date | undefined {
    return this.props.createdAt;
  }
  get updatedAt(): Date | undefined {
    return this.props.updatedAt;
  }

  get isPending(): boolean {
    return this.props.status === TransactionStatus.PENDING;
  }
  get isBroadcasted(): boolean {
    return this.props.status === TransactionStatus.BROADCASTED;
  }
  get isFailed(): boolean {
    return this.props.status === TransactionStatus.FAILED;
  }

  /**
   * 创建新的交易请求
   */
  static create(params: {
    chainType: ChainType;
    sourceService: string;
    sourceOrderId: string;
    fromAddress: EvmAddress;
    toAddress: EvmAddress;
    value: TokenAmount;
    data?: string;
  }): TransactionRequest {
    return new TransactionRequest({
      ...params,
      status: TransactionStatus.PENDING,
      retryCount: 0,
    });
  }

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

  /**
   * 设置签名交易
   */
  setSignedTransaction(signedTx: string, gasLimit: bigint, gasPrice: Decimal, nonce: number): void {
    this.props.signedTx = signedTx;
    this.props.gasLimit = gasLimit;
    this.props.gasPrice = gasPrice;
    this.props.nonce = nonce;
    this.props.status = TransactionStatus.SIGNED;
  }

  /**
   * 标记为已广播
   */
  markAsBroadcasted(txHash: TxHash): void {
    this.props.txHash = txHash;
    this.props.status = TransactionStatus.BROADCASTED;

    this.addDomainEvent(
      new TransactionBroadcastedEvent({
        requestId: this.props.id?.toString() ?? '0',
        chainType: this.props.chainType.toString(),
        txHash: txHash.toString(),
        fromAddress: this.props.fromAddress.toString(),
        toAddress: this.props.toAddress.toString(),
        value: this.props.value.raw.toString(),
        sourceService: this.props.sourceService,
        sourceOrderId: this.props.sourceOrderId,
      }),
    );
  }

  /**
   * 标记为已确认
   */
  markAsConfirmed(): void {
    this.props.status = TransactionStatus.CONFIRMED;
  }

  /**
   * 标记为失败
   */
  markAsFailed(errorMessage: string): void {
    this.props.status = TransactionStatus.FAILED;
    this.props.errorMessage = errorMessage;
    this.props.retryCount += 1;
  }

  /**
   * 重试
   */
  retry(): void {
    this.props.status = TransactionStatus.PENDING;
    this.props.errorMessage = undefined;
    this.props.signedTx = undefined;
    this.props.txHash = undefined;
  }
}
