import { DomainError } from "./errors.ts";

export class Money {
  readonly minor: bigint;
  readonly currency: string;

  private constructor(minor: bigint, currency: string) {
    this.minor = minor;
    this.currency = currency;
  }

  static ofMinor(minor: bigint, currency: string): Money {
    const normalized = currency.trim().toUpperCase();
    if (!/^[A-Z]{3}$/.test(normalized)) throw new DomainError("INVALID_CURRENCY", "Currency must be ISO-4217 style.");
    if (minor < 0n) throw new DomainError("NEGATIVE_MONEY", "Money cannot be negative.");
    return new Money(minor, normalized);
  }

  add(other: Money): Money {
    this.assertCurrency(other);
    return Money.ofMinor(this.minor + other.minor, this.currency);
  }

  subtract(other: Money): Money {
    this.assertCurrency(other);
    if (other.minor > this.minor) throw new DomainError("INSUFFICIENT_AMOUNT", "Result cannot be negative.");
    return Money.ofMinor(this.minor - other.minor, this.currency);
  }

  private assertCurrency(other: Money): void {
    if (other.currency !== this.currency) throw new DomainError("CURRENCY_MISMATCH", "Currencies must match.");
  }
}
