// @vitest-environment node
import { describe, it, expect } from "vitest";
import { debitMatchesBill } from "./billMatch";

// Accrual A/P matching rule: a bank debit settles a bill only when the amount and
// date line up. Mirrors the brief's acceptance tests 5 and 6.
describe("debitMatchesBill", () => {
  const bill = (over: Partial<Parameters<typeof debitMatchesBill>[0]> = {}) => ({
    total: 100, paid_amount: 0, issue_date: "2026-04-15", due_date: "2026-04-15", ...over,
  });

  it("matches a same-amount debit within the ±30 day window (test 5)", () => {
    expect(debitMatchesBill(bill(), { amount: 100, date: "2026-04-20" })).toBe(true);
  });

  it("treats $0.01 differences as a full match", () => {
    expect(debitMatchesBill(bill(), { amount: 100.01, date: "2026-04-15" })).toBe(true);
    expect(debitMatchesBill(bill(), { amount: 99.99, date: "2026-04-15" })).toBe(true);
  });

  it("rejects a debit outside the ±30 day window even if the amount is identical (test 6)", () => {
    // FPL $307.67 billed once in April; identical payments in Jan/Feb must NOT match.
    const b = bill({ total: 307.67, issue_date: "2026-04-15", due_date: "2026-04-15" });
    expect(debitMatchesBill(b, { amount: 307.67, date: "2026-01-26" })).toBe(false);
    expect(debitMatchesBill(b, { amount: 307.67, date: "2026-02-24" })).toBe(false);
    expect(debitMatchesBill(b, { amount: 307.67, date: "2026-04-15" })).toBe(true);
  });

  it("matches a partial payment (debit ≤ remaining balance)", () => {
    expect(debitMatchesBill(bill(), { amount: 40, date: "2026-04-15" })).toBe(true);
  });

  it("respects remaining balance, not the original total", () => {
    const partlyPaid = bill({ total: 100, paid_amount: 60 }); // $40 remaining
    expect(debitMatchesBill(partlyPaid, { amount: 40, date: "2026-04-15" })).toBe(true);
    expect(debitMatchesBill(partlyPaid, { amount: 100, date: "2026-04-15" })).toBe(false); // exceeds remaining
  });

  it("does not match a fully paid bill", () => {
    expect(debitMatchesBill(bill({ total: 100, paid_amount: 100 }), { amount: 100, date: "2026-04-15" })).toBe(false);
  });

  it("uses issue_date when due_date is absent", () => {
    expect(debitMatchesBill(bill({ due_date: null, issue_date: "2026-04-15" }), { amount: 100, date: "2026-05-10" })).toBe(true);
    expect(debitMatchesBill(bill({ due_date: null, issue_date: "2026-04-15" }), { amount: 100, date: "2026-06-01" })).toBe(false);
  });
});
