import Decimal from 'decimal.js';
import { UserId, Money, Hashpower } from '@/domain/value-objects';

export enum PendingRewardStatus {
  PENDING = 'PENDING',
  SETTLED = 'SETTLED',
  EXPIRED = 'EXPIRED',
}

export class PendingReward {
  private readonly _id: bigint;
  private readonly _accountSequence: string;
  private readonly _userId: UserId;
  private readonly _usdtAmount: Money;
  private readonly _hashpowerAmount: Hashpower;
  private readonly _sourceOrderId: string;
  private readonly _allocationType: string;
  private readonly _expireAt: Date;
  private _status: PendingRewardStatus;
  private _settledAt: Date | null;
  private _expiredAt: Date | null;
  private readonly _createdAt: Date;

  private constructor(
    id: bigint,
    accountSequence: string,
    userId: UserId,
    usdtAmount: Money,
    hashpowerAmount: Hashpower,
    sourceOrderId: string,
    allocationType: string,
    expireAt: Date,
    status: PendingRewardStatus,
    settledAt: Date | null,
    expiredAt: Date | null,
    createdAt: Date,
  ) {
    this._id = id;
    this._accountSequence = accountSequence;
    this._userId = userId;
    this._usdtAmount = usdtAmount;
    this._hashpowerAmount = hashpowerAmount;
    this._sourceOrderId = sourceOrderId;
    this._allocationType = allocationType;
    this._expireAt = expireAt;
    this._status = status;
    this._settledAt = settledAt;
    this._expiredAt = expiredAt;
    this._createdAt = createdAt;
  }

  // Getters
  get id(): bigint { return this._id; }
  get accountSequence(): string { return this._accountSequence; }
  get userId(): UserId { return this._userId; }
  get usdtAmount(): Money { return this._usdtAmount; }
  get hashpowerAmount(): Hashpower { return this._hashpowerAmount; }
  get sourceOrderId(): string { return this._sourceOrderId; }
  get allocationType(): string { return this._allocationType; }
  get expireAt(): Date { return this._expireAt; }
  get status(): PendingRewardStatus { return this._status; }
  get settledAt(): Date | null { return this._settledAt; }
  get expiredAt(): Date | null { return this._expiredAt; }
  get createdAt(): Date { return this._createdAt; }

  get isPending(): boolean { return this._status === PendingRewardStatus.PENDING; }
  get isSettled(): boolean { return this._status === PendingRewardStatus.SETTLED; }
  get isExpired(): boolean { return this._status === PendingRewardStatus.EXPIRED; }

  /**
   * 创建新的待领取奖励
   */
  static create(params: {
    accountSequence: string;
    userId: UserId;
    usdtAmount: Money;
    hashpowerAmount: Hashpower;
    sourceOrderId: string;
    allocationType: string;
    expireAt: Date;
  }): PendingReward {
    return new PendingReward(
      BigInt(0), // Will be set by database
      params.accountSequence,
      params.userId,
      params.usdtAmount,
      params.hashpowerAmount,
      params.sourceOrderId,
      params.allocationType,
      params.expireAt,
      PendingRewardStatus.PENDING,
      null,
      null,
      new Date(),
    );
  }

  /**
   * 从数据库重建
   */
  static reconstruct(params: {
    id: bigint;
    accountSequence: string;
    userId: bigint;
    usdtAmount: Decimal;
    hashpowerAmount: Decimal;
    sourceOrderId: string;
    allocationType: string;
    expireAt: Date;
    status: string;
    settledAt: Date | null;
    expiredAt: Date | null;
    createdAt: Date;
  }): PendingReward {
    return new PendingReward(
      params.id,
      params.accountSequence,
      UserId.create(params.userId),
      Money.USDT(params.usdtAmount),
      Hashpower.create(params.hashpowerAmount),
      params.sourceOrderId,
      params.allocationType,
      params.expireAt,
      params.status as PendingRewardStatus,
      params.settledAt,
      params.expiredAt,
      params.createdAt,
    );
  }

  /**
   * 标记为已结算 (用户认种后，待领取转为可结算)
   */
  markAsSettled(): void {
    if (this._status !== PendingRewardStatus.PENDING) {
      throw new Error(`Cannot settle reward in status: ${this._status}`);
    }
    this._status = PendingRewardStatus.SETTLED;
    this._settledAt = new Date();
  }

  /**
   * 标记为已过期 (24小时未认种)
   */
  markAsExpired(): void {
    if (this._status !== PendingRewardStatus.PENDING) {
      throw new Error(`Cannot expire reward in status: ${this._status}`);
    }
    this._status = PendingRewardStatus.EXPIRED;
    this._expiredAt = new Date();
  }

  /**
   * 检查是否已过期
   */
  isOverdue(now: Date = new Date()): boolean {
    return this._status === PendingRewardStatus.PENDING && now > this._expireAt;
  }
}
