export class Money {
  private constructor(
    private readonly amount: string,
    private readonly curr: string,
  ) {}

  static create(amount: string, currency: string = 'USD'): Money {
    const parsed = parseFloat(amount);
    if (isNaN(parsed)) {
      throw new Error('Invalid monetary amount');
    }
    if (!currency || currency.trim().length === 0) {
      throw new Error('Currency cannot be empty');
    }
    if (currency.length > 10) {
      throw new Error('Currency code must not exceed 10 characters');
    }
    return new Money(amount, currency.toUpperCase());
  }

  static zero(currency: string = 'USD'): Money {
    return new Money('0', currency.toUpperCase());
  }

  static fromValues(amount: string, currency: string): Money {
    return new Money(amount, currency);
  }

  get value(): string {
    return this.amount;
  }

  get currency(): string {
    return this.curr;
  }

  get numericValue(): number {
    return parseFloat(this.amount);
  }

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

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

  isNegative(): boolean {
    return this.numericValue < 0;
  }

  add(other: Money): Money {
    this.ensureSameCurrency(other);
    const result = (this.numericValue + other.numericValue).toFixed(8);
    return new Money(result, this.curr);
  }

  subtract(other: Money): Money {
    this.ensureSameCurrency(other);
    const result = (this.numericValue - other.numericValue).toFixed(8);
    return new Money(result, this.curr);
  }

  isGreaterThanOrEqual(other: Money): boolean {
    this.ensureSameCurrency(other);
    return this.numericValue >= other.numericValue;
  }

  equals(other: Money): boolean {
    return this.amount === other.amount && this.curr === other.curr;
  }

  toString(): string {
    return `${this.amount} ${this.curr}`;
  }

  private ensureSameCurrency(other: Money): void {
    if (this.curr !== other.curr) {
      throw new Error(`Currency mismatch: ${this.curr} vs ${other.curr}`);
    }
  }
}
