{"version":3,"sources":["../../src/core/money.ts"],"names":["Money","_Money","cents","currency","amount","multiplier","other","factor","divisor","parts","quotient","remainder","result","i","extra","ratios","total","sum","r","remaining","share","options","showSymbol","showDecimals","symbolPosition","decimal","absValue","isNegative","formatted","intPart","decPart","pos","space","percent","minValue","maxValue","min","max","values","m","intStr"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { Currency, FormatOptions, IMoney } from './types.js';\n\n/**\n * Immutable Money class that uses integer arithmetic for precision\n */\nexport class Money implements IMoney {\n  readonly cents: number;\n  readonly currency: Currency;\n\n  private constructor(cents: number, currency: Currency) {\n    if (!Number.isInteger(cents)) {\n      throw new Error('Money must be created with an integer number of cents');\n    }\n    this.cents = cents;\n    this.currency = currency;\n    Object.freeze(this);\n  }\n\n  /**\n   * Create money from cents (smallest unit)\n   */\n  static fromCents(cents: number, currency: Currency): Money {\n    return new Money(Math.round(cents), currency);\n  }\n\n  /**\n   * Create money from a decimal amount\n   * @example Money.fromDecimal(100.50, USD) creates $100.50\n   */\n  static fromDecimal(amount: number, currency: Currency): Money {\n    const multiplier = Math.pow(10, currency.decimals);\n    const cents = Math.round(amount * multiplier);\n    return new Money(cents, currency);\n  }\n\n  /**\n   * Create zero money\n   */\n  static zero(currency: Currency): Money {\n    return new Money(0, currency);\n  }\n\n  /**\n   * Add another money value (must be same currency)\n   */\n  add(other: IMoney): Money {\n    this.assertSameCurrency(other);\n    return new Money(this.cents + other.cents, this.currency);\n  }\n\n  /**\n   * Subtract another money value (must be same currency)\n   */\n  subtract(other: IMoney): Money {\n    this.assertSameCurrency(other);\n    return new Money(this.cents - other.cents, this.currency);\n  }\n\n  /**\n   * Multiply by a factor (rounds to nearest cent)\n   */\n  multiply(factor: number): Money {\n    return new Money(Math.round(this.cents * factor), this.currency);\n  }\n\n  /**\n   * Divide by a divisor (rounds to nearest cent)\n   */\n  divide(divisor: number): Money {\n    if (divisor === 0) {\n      throw new Error('Cannot divide by zero');\n    }\n    return new Money(Math.round(this.cents / divisor), this.currency);\n  }\n\n  /**\n   * Distribute money evenly without losing cents\n   * The remainder is distributed to the first parts\n   * @example $100 / 3 = [$33.34, $33.33, $33.33]\n   */\n  distribute(parts: number): Money[] {\n    if (parts <= 0 || !Number.isInteger(parts)) {\n      throw new Error('Parts must be a positive integer');\n    }\n\n    const quotient = Math.floor(this.cents / parts);\n    const remainder = this.cents % parts;\n\n    const result: Money[] = [];\n    for (let i = 0; i < parts; i++) {\n      // Add 1 cent to the first 'remainder' parts\n      const extra = i < remainder ? 1 : 0;\n      result.push(new Money(quotient + extra, this.currency));\n    }\n\n    return result;\n  }\n\n  /**\n   * Distribute money according to ratios\n   * @example $100 with ratios [1, 2, 2] = [$20, $40, $40]\n   */\n  distributeByRatios(ratios: number[]): Money[] {\n    if (ratios.length === 0) {\n      throw new Error('Ratios array cannot be empty');\n    }\n\n    const total = ratios.reduce((sum, r) => sum + r, 0);\n    if (total <= 0) {\n      throw new Error('Sum of ratios must be positive');\n    }\n\n    let remaining = this.cents;\n    const result: Money[] = [];\n\n    for (let i = 0; i < ratios.length; i++) {\n      if (i === ratios.length - 1) {\n        // Last part gets whatever is remaining to avoid rounding errors\n        result.push(new Money(remaining, this.currency));\n      } else {\n        const share = Math.round((this.cents * ratios[i]) / total);\n        result.push(new Money(share, this.currency));\n        remaining -= share;\n      }\n    }\n\n    return result;\n  }\n\n  /**\n   * Format money for display\n   */\n  format(options: FormatOptions = {}): string {\n    const { showSymbol = true, showDecimals = true, symbolPosition } = options;\n\n    const decimal = this.toDecimal();\n    const absValue = Math.abs(decimal);\n    const isNegative = decimal < 0;\n\n    // Format the number\n    let formatted: string;\n    if (showDecimals && this.currency.decimals > 0) {\n      const [intPart, decPart] = absValue.toFixed(this.currency.decimals).split('.');\n      const intFormatted = this.formatInteger(intPart);\n      formatted = `${intFormatted}${this.currency.decimalSeparator}${decPart}`;\n    } else {\n      formatted = this.formatInteger(Math.round(absValue).toString());\n    }\n\n    // Add negative sign\n    if (isNegative) {\n      formatted = `-${formatted}`;\n    }\n\n    // Add symbol\n    if (showSymbol) {\n      const pos = symbolPosition ?? this.currency.symbolPosition;\n      const space = this.currency.symbolSpacing ? ' ' : '';\n\n      if (pos === 'before') {\n        formatted = `${this.currency.symbol}${space}${formatted}`;\n      } else {\n        formatted = `${formatted}${space}${this.currency.symbol}`;\n      }\n    }\n\n    return formatted;\n  }\n\n  /**\n   * Get the decimal representation\n   */\n  toDecimal(): number {\n    return this.cents / Math.pow(10, this.currency.decimals);\n  }\n\n  /**\n   * Check equality with another money value\n   */\n  equals(other: IMoney): boolean {\n    return this.cents === other.cents && this.currency.code === other.currency.code;\n  }\n\n  /**\n   * Check if greater than another money value\n   */\n  greaterThan(other: IMoney): boolean {\n    this.assertSameCurrency(other);\n    return this.cents > other.cents;\n  }\n\n  /**\n   * Check if less than another money value\n   */\n  lessThan(other: IMoney): boolean {\n    this.assertSameCurrency(other);\n    return this.cents < other.cents;\n  }\n\n  /**\n   * Check if greater than or equal\n   */\n  greaterThanOrEqual(other: IMoney): boolean {\n    this.assertSameCurrency(other);\n    return this.cents >= other.cents;\n  }\n\n  /**\n   * Check if less than or equal\n   */\n  lessThanOrEqual(other: IMoney): boolean {\n    this.assertSameCurrency(other);\n    return this.cents <= other.cents;\n  }\n\n  /**\n   * Check if zero\n   */\n  isZero(): boolean {\n    return this.cents === 0;\n  }\n\n  /**\n   * Check if positive\n   */\n  isPositive(): boolean {\n    return this.cents > 0;\n  }\n\n  /**\n   * Check if negative\n   */\n  isNegative(): boolean {\n    return this.cents < 0;\n  }\n\n  /**\n   * Get absolute value\n   */\n  abs(): Money {\n    return new Money(Math.abs(this.cents), this.currency);\n  }\n\n  /**\n   * Negate the value\n   */\n  negate(): Money {\n    return new Money(-this.cents, this.currency);\n  }\n\n  /**\n   * Calculate a percentage of this money\n   * @example money.percentage(10) returns 10% of the amount\n   */\n  percentage(percent: number): Money {\n    return new Money(Math.round((this.cents * percent) / 100), this.currency);\n  }\n\n  /**\n   * Add a percentage to this money\n   * @example money.addPercentage(19) adds 19% (like tax)\n   */\n  addPercentage(percent: number): Money {\n    return this.add(this.percentage(percent));\n  }\n\n  /**\n   * Subtract a percentage from this money\n   * @example money.subtractPercentage(10) subtracts 10% (like discount)\n   */\n  subtractPercentage(percent: number): Money {\n    return this.subtract(this.percentage(percent));\n  }\n\n  /**\n   * Get the minimum of this and another money value\n   */\n  min(other: IMoney): Money {\n    this.assertSameCurrency(other);\n    return this.cents <= other.cents ? this : new Money(other.cents, this.currency);\n  }\n\n  /**\n   * Get the maximum of this and another money value\n   */\n  max(other: IMoney): Money {\n    this.assertSameCurrency(other);\n    return this.cents >= other.cents ? this : new Money(other.cents, this.currency);\n  }\n\n  /**\n   * Clamp this money between a minimum and maximum\n   */\n  clamp(minValue: IMoney, maxValue: IMoney): Money {\n    return this.max(minValue).min(maxValue);\n  }\n\n  /**\n   * Get cents (smallest unit)\n   */\n  toCents(): number {\n    return this.cents;\n  }\n\n  /**\n   * Check if within a range (inclusive)\n   */\n  isBetween(min: IMoney, max: IMoney): boolean {\n    this.assertSameCurrency(min);\n    this.assertSameCurrency(max);\n    return this.cents >= min.cents && this.cents <= max.cents;\n  }\n\n  /**\n   * Sum multiple money values\n   */\n  static sum(values: IMoney[]): Money {\n    if (values.length === 0) {\n      throw new Error('Cannot sum empty array');\n    }\n    const currency = values[0].currency;\n    const total = values.reduce((sum, m) => {\n      if (m.currency.code !== currency.code) {\n        throw new Error('Cannot sum different currencies');\n      }\n      return sum + m.cents;\n    }, 0);\n    return new Money(total, currency);\n  }\n\n  /**\n   * Get the minimum from an array of money values\n   */\n  static minimum(values: IMoney[]): Money {\n    if (values.length === 0) {\n      throw new Error('Cannot get minimum of empty array');\n    }\n    return values.reduce((min, m) => (m.cents < min.cents ? m : min)) as Money;\n  }\n\n  /**\n   * Get the maximum from an array of money values\n   */\n  static maximum(values: IMoney[]): Money {\n    if (values.length === 0) {\n      throw new Error('Cannot get maximum of empty array');\n    }\n    return values.reduce((max, m) => (m.cents > max.cents ? m : max)) as Money;\n  }\n\n  /**\n   * Calculate the average of money values\n   */\n  static average(values: IMoney[]): Money {\n    if (values.length === 0) {\n      throw new Error('Cannot calculate average of empty array');\n    }\n    const total = Money.sum(values);\n    return total.divide(values.length);\n  }\n\n  /**\n   * Convert to JSON-serializable object\n   */\n  toJSON(): { cents: number; currency: string } {\n    return {\n      cents: this.cents,\n      currency: this.currency.code,\n    };\n  }\n\n  /**\n   * String representation\n   */\n  toString(): string {\n    return this.format();\n  }\n\n  private formatInteger(intStr: string): string {\n    const parts: string[] = [];\n    let remaining = intStr;\n\n    while (remaining.length > 3) {\n      parts.unshift(remaining.slice(-3));\n      remaining = remaining.slice(0, -3);\n    }\n\n    if (remaining) {\n      parts.unshift(remaining);\n    }\n\n    return parts.join(this.currency.thousandsSeparator);\n  }\n\n  private assertSameCurrency(other: IMoney): void {\n    if (this.currency.code !== other.currency.code) {\n      throw new Error(\n        `Cannot perform operation with different currencies: ${this.currency.code} and ${other.currency.code}`\n      );\n    }\n  }\n}\n"]}