// Unit tests for the amount-in-words converter (Task 3 of
// docs/superpowers/plans/2026-08-01-ap.md; docs/superpowers/specs/
// 2026-08-01-ap-design.md's check-printing section). Pure functions, no DB —
// same style as tests/server/errors.test.ts.

import { describe, it, expect } from "vitest";
import { amountToWords, centsFromAmountString } from "../../server/src/lib/amountWords.js";

describe("amountToWords", () => {
  it.each<[string, bigint, string]>([
    ["0.99", 99n, "Zero and 99/100 dollars"],
    ["13.00", 1300n, "Thirteen and 00/100 dollars"],
    ["40.00", 4000n, "Forty and 00/100 dollars"],
    ["100.00", 10000n, "One hundred and 00/100 dollars"],
    ["1050.07", 105007n, "One thousand fifty and 07/100 dollars"],
    ["1000000.00", 100000000n, "One million and 00/100 dollars"],
    ["12345.67", 1234567n, "Twelve thousand three hundred forty-five and 67/100 dollars"],
    ["0.01", 1n, "Zero and 01/100 dollars"],
    ["20.00", 2000n, "Twenty and 00/100 dollars"],
    ["115.10", 11510n, "One hundred fifteen and 10/100 dollars"],
  ])("%s -> %s", (_label, cents, expected) => {
    expect(amountToWords(cents)).toBe(expected);
  });

  it("hyphenates a two-word tens-and-ones amount (42 -> forty-two)", () => {
    expect(amountToWords(4200n)).toBe("Forty-two and 00/100 dollars");
  });

  it("handles a teen correctly (no hyphen, no 'ty')", () => {
    expect(amountToWords(1900n)).toBe("Nineteen and 00/100 dollars");
  });

  it("handles an exact hundred with no remainder in the tens/ones", () => {
    expect(amountToWords(20000n)).toBe("Two hundred and 00/100 dollars");
  });

  it("skips an empty thousands group inside a larger number", () => {
    // 1,000,050 -> "one million fifty" (the thousands group is empty and
    // contributes no "thousand" at all, per dollarsToWords' documented
    // per-group skip).
    expect(amountToWords(100005000n)).toBe("One million fifty and 00/100 dollars");
  });

  it("throws on a negative cents value", () => {
    expect(() => amountToWords(-1n)).toThrow(/non-negative/);
  });
});

describe("centsFromAmountString", () => {
  it.each<[string, bigint]>([
    ["1234.5600", 123456n],
    ["0.0000", 0n],
    ["100.0000", 10000n],
    ["5.0100", 501n],
    ["-40.0000", -4000n],
  ])("%s -> %s cents", (amount, expected) => {
    expect(centsFromAmountString(amount)).toBe(expected);
  });

  it("round-trips through amountToWords for a typical stored amount", () => {
    expect(amountToWords(centsFromAmountString("1050.0700"))).toBe(
      "One thousand fifty and 07/100 dollars",
    );
  });
});
