import { Money } from '../value-objects/money.vo';

export enum TradingTransactionType {
  TRANSFER_IN = 'TRANSFER_IN',
  TRANSFER_OUT = 'TRANSFER_OUT',
  BUY = 'BUY',
  SELL = 'SELL',
  FREEZE = 'FREEZE',
  UNFREEZE = 'UNFREEZE',
  DEPOSIT = 'DEPOSIT',
  WITHDRAW = 'WITHDRAW',
}

export enum AssetType {
  SHARE = 'SHARE',
  CASH = 'CASH',
}

export interface TradingTransaction {
  type: TradingTransactionType;
  assetType: AssetType;
  amount: Money;
  balanceBefore: Money;
  balanceAfter: Money;
  referenceId?: string;
  referenceType?: string;
  description?: string;
  createdAt: Date;
}

export class TradingAccountAggregate {
  private _id: string | null;
  private _accountSequence: string;
  private _shareBalance: Money;
  private _cashBalance: Money;
  private _frozenShares: Money;
  private _frozenCash: Money;
  private _totalBought: Money;
  private _totalSold: Money;
  private _pendingTransactions: TradingTransaction[] = [];

  private constructor(
    accountSequence: string,
    shareBalance: Money,
    cashBalance: Money,
    frozenShares: Money,
    frozenCash: Money,
    totalBought: Money,
    totalSold: Money,
    id: string | null = null,
  ) {
    this._id = id;
    this._accountSequence = accountSequence;
    this._shareBalance = shareBalance;
    this._cashBalance = cashBalance;
    this._frozenShares = frozenShares;
    this._frozenCash = frozenCash;
    this._totalBought = totalBought;
    this._totalSold = totalSold;
  }

  static create(accountSequence: string): TradingAccountAggregate {
    return new TradingAccountAggregate(
      accountSequence,
      Money.zero(),
      Money.zero(),
      Money.zero(),
      Money.zero(),
      Money.zero(),
      Money.zero(),
    );
  }

  static reconstitute(props: {
    id: string;
    accountSequence: string;
    shareBalance: Money;
    cashBalance: Money;
    frozenShares: Money;
    frozenCash: Money;
    totalBought: Money;
    totalSold: Money;
  }): TradingAccountAggregate {
    return new TradingAccountAggregate(
      props.accountSequence,
      props.shareBalance,
      props.cashBalance,
      props.frozenShares,
      props.frozenCash,
      props.totalBought,
      props.totalSold,
      props.id,
    );
  }

  // Getters
  get id(): string | null { return this._id; }
  get accountSequence(): string { return this._accountSequence; }
  get shareBalance(): Money { return this._shareBalance; }
  get cashBalance(): Money { return this._cashBalance; }
  get frozenShares(): Money { return this._frozenShares; }
  get frozenCash(): Money { return this._frozenCash; }
  get availableShares(): Money { return this._shareBalance.subtract(this._frozenShares); }
  get availableCash(): Money { return this._cashBalance.subtract(this._frozenCash); }
  get totalBought(): Money { return this._totalBought; }
  get totalSold(): Money { return this._totalSold; }
  get pendingTransactions(): TradingTransaction[] { return [...this._pendingTransactions]; }

  // 从挖矿账户划入积分股
  transferSharesIn(amount: Money, referenceId: string): void {
    const balanceBefore = this._shareBalance;
    this._shareBalance = this._shareBalance.add(amount);
    this._pendingTransactions.push({
      type: TradingTransactionType.TRANSFER_IN,
      assetType: AssetType.SHARE,
      amount,
      balanceBefore,
      balanceAfter: this._shareBalance,
      referenceId,
      referenceType: 'TRANSFER',
      description: '从挖矿账户划入',
      createdAt: new Date(),
    });
  }

  // 划出积分股到挖矿账户
  transferSharesOut(amount: Money, referenceId: string): void {
    if (this.availableShares.isLessThan(amount)) {
      throw new Error('Insufficient available shares');
    }
    const balanceBefore = this._shareBalance;
    this._shareBalance = this._shareBalance.subtract(amount);
    this._pendingTransactions.push({
      type: TradingTransactionType.TRANSFER_OUT,
      assetType: AssetType.SHARE,
      amount,
      balanceBefore,
      balanceAfter: this._shareBalance,
      referenceId,
      referenceType: 'TRANSFER',
      description: '划出到挖矿账户',
      createdAt: new Date(),
    });
  }

  // 冻结积分股（卖单）
  freezeShares(amount: Money, orderId: string): void {
    if (this.availableShares.isLessThan(amount)) {
      throw new Error('Insufficient available shares to freeze');
    }
    const balanceBefore = this._shareBalance;
    this._frozenShares = this._frozenShares.add(amount);
    this._pendingTransactions.push({
      type: TradingTransactionType.FREEZE,
      assetType: AssetType.SHARE,
      amount,
      balanceBefore,
      balanceAfter: this._shareBalance,
      referenceId: orderId,
      referenceType: 'ORDER',
      description: '卖单冻结',
      createdAt: new Date(),
    });
  }

  // 解冻积分股（订单取消）
  unfreezeShares(amount: Money, orderId: string): void {
    if (this._frozenShares.isLessThan(amount)) {
      throw new Error('Insufficient frozen shares');
    }
    const balanceBefore = this._shareBalance;
    this._frozenShares = this._frozenShares.subtract(amount);
    this._pendingTransactions.push({
      type: TradingTransactionType.UNFREEZE,
      assetType: AssetType.SHARE,
      amount,
      balanceBefore,
      balanceAfter: this._shareBalance,
      referenceId: orderId,
      referenceType: 'ORDER',
      description: '订单取消解冻',
      createdAt: new Date(),
    });
  }

  // 冻结现金（买单）
  freezeCash(amount: Money, orderId: string): void {
    if (this.availableCash.isLessThan(amount)) {
      throw new Error('Insufficient available cash to freeze');
    }
    const balanceBefore = this._cashBalance;
    this._frozenCash = this._frozenCash.add(amount);
    this._pendingTransactions.push({
      type: TradingTransactionType.FREEZE,
      assetType: AssetType.CASH,
      amount,
      balanceBefore,
      balanceAfter: this._cashBalance,
      referenceId: orderId,
      referenceType: 'ORDER',
      description: '买单冻结',
      createdAt: new Date(),
    });
  }

  // 解冻现金（订单取消）
  unfreezeCash(amount: Money, orderId: string): void {
    if (this._frozenCash.isLessThan(amount)) {
      throw new Error('Insufficient frozen cash');
    }
    const balanceBefore = this._cashBalance;
    this._frozenCash = this._frozenCash.subtract(amount);
    this._pendingTransactions.push({
      type: TradingTransactionType.UNFREEZE,
      assetType: AssetType.CASH,
      amount,
      balanceBefore,
      balanceAfter: this._cashBalance,
      referenceId: orderId,
      referenceType: 'ORDER',
      description: '订单取消解冻',
      createdAt: new Date(),
    });
  }

  // 卖出成交
  executeSell(shareAmount: Money, cashAmount: Money, tradeId: string): void {
    if (this._frozenShares.isLessThan(shareAmount)) {
      throw new Error('Insufficient frozen shares for trade');
    }
    const shareBalanceBefore = this._shareBalance;
    this._frozenShares = this._frozenShares.subtract(shareAmount);
    this._shareBalance = this._shareBalance.subtract(shareAmount);
    this._cashBalance = this._cashBalance.add(cashAmount);
    this._totalSold = this._totalSold.add(shareAmount);

    this._pendingTransactions.push({
      type: TradingTransactionType.SELL,
      assetType: AssetType.SHARE,
      amount: shareAmount,
      balanceBefore: shareBalanceBefore,
      balanceAfter: this._shareBalance,
      referenceId: tradeId,
      referenceType: 'TRADE',
      description: '卖出成交',
      createdAt: new Date(),
    });
  }

  // 买入成交
  executeBuy(shareAmount: Money, cashAmount: Money, tradeId: string): void {
    if (this._frozenCash.isLessThan(cashAmount)) {
      throw new Error('Insufficient frozen cash for trade');
    }
    const cashBalanceBefore = this._cashBalance;
    this._frozenCash = this._frozenCash.subtract(cashAmount);
    this._cashBalance = this._cashBalance.subtract(cashAmount);
    this._shareBalance = this._shareBalance.add(shareAmount);
    this._totalBought = this._totalBought.add(shareAmount);

    this._pendingTransactions.push({
      type: TradingTransactionType.BUY,
      assetType: AssetType.SHARE,
      amount: shareAmount,
      balanceBefore: new Money(cashBalanceBefore.value),
      balanceAfter: this._cashBalance,
      referenceId: tradeId,
      referenceType: 'TRADE',
      description: '买入成交',
      createdAt: new Date(),
    });
  }

  // 充值现金
  deposit(amount: Money, referenceId: string): void {
    const balanceBefore = this._cashBalance;
    this._cashBalance = this._cashBalance.add(amount);
    this._pendingTransactions.push({
      type: TradingTransactionType.DEPOSIT,
      assetType: AssetType.CASH,
      amount,
      balanceBefore,
      balanceAfter: this._cashBalance,
      referenceId,
      referenceType: 'DEPOSIT',
      description: '充值',
      createdAt: new Date(),
    });
  }

  // 提现现金
  withdraw(amount: Money, referenceId: string): void {
    if (this.availableCash.isLessThan(amount)) {
      throw new Error('Insufficient available cash for withdrawal');
    }
    const balanceBefore = this._cashBalance;
    this._cashBalance = this._cashBalance.subtract(amount);
    this._pendingTransactions.push({
      type: TradingTransactionType.WITHDRAW,
      assetType: AssetType.CASH,
      amount,
      balanceBefore,
      balanceAfter: this._cashBalance,
      referenceId,
      referenceType: 'WITHDRAW',
      description: '提现',
      createdAt: new Date(),
    });
  }

  // 充值积分股（做市商用）
  depositShares(amount: Money, referenceId: string): void {
    const balanceBefore = this._shareBalance;
    this._shareBalance = this._shareBalance.add(amount);
    this._pendingTransactions.push({
      type: TradingTransactionType.DEPOSIT,
      assetType: AssetType.SHARE,
      amount,
      balanceBefore,
      balanceAfter: this._shareBalance,
      referenceId,
      referenceType: 'DEPOSIT',
      description: '积分股充值',
      createdAt: new Date(),
    });
  }

  // 提取积分股（做市商用）
  withdrawShares(amount: Money, referenceId: string): void {
    if (this.availableShares.isLessThan(amount)) {
      throw new Error('Insufficient available shares for withdrawal');
    }
    const balanceBefore = this._shareBalance;
    this._shareBalance = this._shareBalance.subtract(amount);
    this._pendingTransactions.push({
      type: TradingTransactionType.WITHDRAW,
      assetType: AssetType.SHARE,
      amount,
      balanceBefore,
      balanceAfter: this._shareBalance,
      referenceId,
      referenceType: 'WITHDRAW',
      description: '积分股提取',
      createdAt: new Date(),
    });
  }

  clearPendingTransactions(): void {
    this._pendingTransactions = [];
  }
}
