import { ShareAmount } from '../value-objects/share-amount.vo';

export enum MiningTransactionType {
  MINE = 'MINE',
  FREEZE = 'FREEZE',
  UNFREEZE = 'UNFREEZE',
  TRANSFER_OUT = 'TRANSFER_OUT',
  TRANSFER_IN = 'TRANSFER_IN',
  BURN = 'BURN',
  MANUAL_MINING = 'MANUAL_MINING', // 手工补发挖矿
}

export interface MiningTransaction {
  type: MiningTransactionType;
  amount: ShareAmount;
  balanceBefore: ShareAmount;
  balanceAfter: ShareAmount;
  referenceId?: string;
  referenceType?: string;
  description?: string;
  createdAt: Date;
}

/**
 * 挖矿账户聚合根
 */
export class MiningAccountAggregate {
  private _id: string | null;
  private _accountSequence: string;
  private _totalMined: ShareAmount;
  private _availableBalance: ShareAmount;
  private _frozenBalance: ShareAmount;
  private _totalContribution: ShareAmount;
  private _lastSyncedAt: Date | null;
  private _pendingTransactions: MiningTransaction[] = [];

  private constructor(
    accountSequence: string,
    totalMined: ShareAmount,
    availableBalance: ShareAmount,
    frozenBalance: ShareAmount,
    totalContribution: ShareAmount,
    lastSyncedAt: Date | null,
    id: string | null = null,
  ) {
    this._id = id;
    this._accountSequence = accountSequence;
    this._totalMined = totalMined;
    this._availableBalance = availableBalance;
    this._frozenBalance = frozenBalance;
    this._totalContribution = totalContribution;
    this._lastSyncedAt = lastSyncedAt;
  }

  static create(accountSequence: string): MiningAccountAggregate {
    return new MiningAccountAggregate(
      accountSequence,
      ShareAmount.zero(),
      ShareAmount.zero(),
      ShareAmount.zero(),
      ShareAmount.zero(),
      null,
    );
  }

  static reconstitute(props: {
    id: string;
    accountSequence: string;
    totalMined: ShareAmount;
    availableBalance: ShareAmount;
    frozenBalance: ShareAmount;
    totalContribution: ShareAmount;
    lastSyncedAt: Date | null;
  }): MiningAccountAggregate {
    return new MiningAccountAggregate(
      props.accountSequence,
      props.totalMined,
      props.availableBalance,
      props.frozenBalance,
      props.totalContribution,
      props.lastSyncedAt,
      props.id,
    );
  }

  // Getters
  get id(): string | null {
    return this._id;
  }

  get accountSequence(): string {
    return this._accountSequence;
  }

  get totalMined(): ShareAmount {
    return this._totalMined;
  }

  get availableBalance(): ShareAmount {
    return this._availableBalance;
  }

  get frozenBalance(): ShareAmount {
    return this._frozenBalance;
  }

  get totalBalance(): ShareAmount {
    return this._availableBalance.add(this._frozenBalance);
  }

  get totalContribution(): ShareAmount {
    return this._totalContribution;
  }

  get lastSyncedAt(): Date | null {
    return this._lastSyncedAt;
  }

  get pendingTransactions(): MiningTransaction[] {
    return [...this._pendingTransactions];
  }

  /**
   * 挖矿收入
   */
  mine(amount: ShareAmount, description?: string): void {
    if (amount.isZero()) return;

    const balanceBefore = this._availableBalance;
    this._totalMined = this._totalMined.add(amount);
    this._availableBalance = this._availableBalance.add(amount);

    this._pendingTransactions.push({
      type: MiningTransactionType.MINE,
      amount,
      balanceBefore,
      balanceAfter: this._availableBalance,
      description: description || '挖矿收入',
      createdAt: new Date(),
    });
  }

  /**
   * 手工补发挖矿收入
   */
  manualMine(amount: ShareAmount, referenceId: string, description: string): void {
    if (amount.isZero()) return;

    const balanceBefore = this._availableBalance;
    this._totalMined = this._totalMined.add(amount);
    this._availableBalance = this._availableBalance.add(amount);

    this._pendingTransactions.push({
      type: MiningTransactionType.MANUAL_MINING,
      amount,
      balanceBefore,
      balanceAfter: this._availableBalance,
      referenceId,
      referenceType: 'MANUAL_MINING',
      description,
      createdAt: new Date(),
    });
  }

  /**
   * 冻结余额（用于交易挂单）
   */
  freeze(amount: ShareAmount, referenceId: string, referenceType: string): void {
    if (this._availableBalance.isLessThan(amount)) {
      throw new Error('Insufficient available balance to freeze');
    }

    const balanceBefore = this._availableBalance;
    this._availableBalance = this._availableBalance.subtract(amount);
    this._frozenBalance = this._frozenBalance.add(amount);

    this._pendingTransactions.push({
      type: MiningTransactionType.FREEZE,
      amount,
      balanceBefore,
      balanceAfter: this._availableBalance,
      referenceId,
      referenceType,
      description: '冻结余额',
      createdAt: new Date(),
    });
  }

  /**
   * 解冻余额（订单取消）
   */
  unfreeze(amount: ShareAmount, referenceId: string, referenceType: string): void {
    if (this._frozenBalance.isLessThan(amount)) {
      throw new Error('Insufficient frozen balance to unfreeze');
    }

    const balanceBefore = this._availableBalance;
    this._frozenBalance = this._frozenBalance.subtract(amount);
    this._availableBalance = this._availableBalance.add(amount);

    this._pendingTransactions.push({
      type: MiningTransactionType.UNFREEZE,
      amount,
      balanceBefore,
      balanceAfter: this._availableBalance,
      referenceId,
      referenceType,
      description: '解冻余额',
      createdAt: new Date(),
    });
  }

  /**
   * 转出（交易成交）
   */
  transferOut(amount: ShareAmount, referenceId: string, referenceType: string, fromFrozen: boolean = true): void {
    const balanceBefore = this._availableBalance;

    if (fromFrozen) {
      if (this._frozenBalance.isLessThan(amount)) {
        throw new Error('Insufficient frozen balance to transfer');
      }
      this._frozenBalance = this._frozenBalance.subtract(amount);
    } else {
      if (this._availableBalance.isLessThan(amount)) {
        throw new Error('Insufficient available balance to transfer');
      }
      this._availableBalance = this._availableBalance.subtract(amount);
    }

    this._pendingTransactions.push({
      type: MiningTransactionType.TRANSFER_OUT,
      amount,
      balanceBefore,
      balanceAfter: this._availableBalance,
      referenceId,
      referenceType,
      description: '转出',
      createdAt: new Date(),
    });
  }

  /**
   * 转入（交易成交买入）
   */
  transferIn(amount: ShareAmount, referenceId: string, referenceType: string): void {
    const balanceBefore = this._availableBalance;
    this._availableBalance = this._availableBalance.add(amount);

    this._pendingTransactions.push({
      type: MiningTransactionType.TRANSFER_IN,
      amount,
      balanceBefore,
      balanceAfter: this._availableBalance,
      referenceId,
      referenceType,
      description: '转入',
      createdAt: new Date(),
    });
  }

  /**
   * 更新算力
   */
  updateContribution(contribution: ShareAmount): void {
    this._totalContribution = contribution;
    this._lastSyncedAt = new Date();
  }

  /**
   * 清空待处理交易
   */
  clearPendingTransactions(): void {
    this._pendingTransactions = [];
  }

  toSnapshot(): {
    accountSequence: string;
    totalMined: ShareAmount;
    availableBalance: ShareAmount;
    frozenBalance: ShareAmount;
    totalContribution: ShareAmount;
    lastSyncedAt: Date | null;
  } {
    return {
      accountSequence: this._accountSequence,
      totalMined: this._totalMined,
      availableBalance: this._availableBalance,
      frozenBalance: this._frozenBalance,
      totalContribution: this._totalContribution,
      lastSyncedAt: this._lastSyncedAt,
    };
  }
}
