import { Decimal } from '@prisma/client/runtime/library';

/**
 * 代币金额值对象
 */
export class TokenAmount {
  private readonly _raw: bigint;
  private readonly _decimals: number;

  private constructor(raw: bigint, decimals: number) {
    this._raw = raw;
    this._decimals = decimals;
  }

  /**
   * 从原始值创建（链上格式）
   */
  static fromRaw(raw: bigint, decimals: number = 18): TokenAmount {
    return new TokenAmount(raw, decimals);
  }

  /**
   * 从格式化值创建（人类可读格式）
   */
  static fromFormatted(formatted: string, decimals: number = 18): TokenAmount {
    const [intPart, decPart = ''] = formatted.split('.');
    const paddedDec = decPart.padEnd(decimals, '0').slice(0, decimals);
    const raw = BigInt(intPart + paddedDec);
    return new TokenAmount(raw, decimals);
  }

  /**
   * 从 Decimal 创建
   */
  static fromDecimal(decimal: Decimal, decimals: number = 18): TokenAmount {
    const raw = BigInt(decimal.toFixed(0));
    return new TokenAmount(raw, decimals);
  }

  get raw(): bigint {
    return this._raw;
  }

  get decimals(): number {
    return this._decimals;
  }

  /**
   * 获取格式化值
   */
  get formatted(): string {
    const rawStr = this._raw.toString().padStart(this._decimals + 1, '0');
    const intPart = rawStr.slice(0, -this._decimals) || '0';
    const decPart = rawStr.slice(-this._decimals);
    // 移除尾随零
    const trimmedDec = decPart.replace(/0+$/, '');
    return trimmedDec ? `${intPart}.${trimmedDec}` : intPart;
  }

  /**
   * 获取固定小数位格式
   */
  toFixed(places: number = 8): string {
    const rawStr = this._raw.toString().padStart(this._decimals + 1, '0');
    const intPart = rawStr.slice(0, -this._decimals) || '0';
    const decPart = rawStr.slice(-this._decimals).padEnd(places, '0').slice(0, places);
    return `${intPart}.${decPart}`;
  }

  /**
   * 转为 Decimal（用于数据库存储）
   */
  toDecimal(): Decimal {
    return new Decimal(this._raw.toString());
  }

  /**
   * 转为格式化 Decimal
   */
  toFormattedDecimal(): Decimal {
    return new Decimal(this.toFixed(8));
  }

  equals(other: TokenAmount): boolean {
    return this._raw === other._raw && this._decimals === other._decimals;
  }

  isZero(): boolean {
    return this._raw === 0n;
  }

  isPositive(): boolean {
    return this._raw > 0n;
  }

  toString(): string {
    return this.formatted;
  }
}
