// Generated by bynkc — do not edit by hand.
// commons commerce.money

import { Ok, Err, Some, None, type Result, type Option, type ValidationError } from "./runtime.js";

export type CurrencyCode = string & { readonly __brand: "CurrencyCode" };

export const CurrencyCode = {
  of(value: string): Result<CurrencyCode, ValidationError> {
    if (!new RegExp("^" + "[A-Z]{3}" + "$").test(value)) {
      return Err({ field: "CurrencyCode", message: "must match /[A-Z]{3}/", value });
    }
    return Ok(value as CurrencyCode);
  },
  unsafe(value: string): CurrencyCode {
    return value as CurrencyCode;
  },
};

export interface Money {
  readonly minorUnits: number;
  readonly currency: CurrencyCode;
}

export const Money = {
  zero(currency: CurrencyCode): Money {
    return { minorUnits: 0, currency };
  },
  add(self: Money, other: Money): Result<Money, MoneyError> {
    return (self.currency !== other.currency ? Err(MoneyError.CurrencyMismatch) : Ok({ minorUnits: self.minorUnits + other.minorUnits, currency: self.currency }));
  },
  subtract(self: Money, other: Money): Result<Money, MoneyError> {
    return (self.currency !== other.currency ? Err(MoneyError.CurrencyMismatch) : (self.minorUnits < other.minorUnits ? Err(MoneyError.InsufficientFunds) : Ok({ minorUnits: self.minorUnits - other.minorUnits, currency: self.currency })));
  },
  multiplyBy(self: Money, factor: number): Money {
    return { minorUnits: self.minorUnits * factor, currency: self.currency };
  },
  equals(self: Money, other: Money): boolean {
    return self.currency === other.currency && self.minorUnits === other.minorUnits;
  },
  lessThan(self: Money, other: Money): Result<boolean, MoneyError> {
    return (self.currency !== other.currency ? Err(MoneyError.CurrencyMismatch) : Ok(self.minorUnits < other.minorUnits));
  },
  isZero(self: Money): boolean {
    return self.minorUnits === 0;
  },
};

export type MoneyError =
    { readonly tag: "CurrencyMismatch" }
  | { readonly tag: "InsufficientFunds" }
  | { readonly tag: "Overflow" };

export const MoneyError = {
  CurrencyMismatch: { tag: "CurrencyMismatch" } as MoneyError,
  InsufficientFunds: { tag: "InsufficientFunds" } as MoneyError,
  Overflow: { tag: "Overflow" } as MoneyError,
};

