import { describe, expect, it } from "vitest";
import { buildReconciliationCandidates } from "../src/reconciliation.js";

const PINNED = new Date("2026-08-07T00:00:00.000Z");

function baseItem(overrides: Partial<Parameters<typeof buildReconciliationCandidates>[0][number]> = {}) {
  return {
    id: "itm-1",
    displayName: "Mjölk",
    quantity: 1,
    unit: "l",
    locationName: "Kylen",
    confidence: 1,
    verifiedByUser: true,
    lastVerifiedAt: PINNED,
    updatedAt: PINNED,
    ...overrides,
  };
}

describe("buildReconciliationCandidates", () => {
  it("returns empty when no items match", () => {
    const result = buildReconciliationCandidates(
      [baseItem({ quantity: 0, depletedAt: PINNED })],
      { plannedRecipeIngredientIds: new Map(), daysLeftByItemId: new Map(), dailyConsumptionRate: new Map(), priceMinorByItemId: new Map() },
      PINNED,
    );
    expect(result).toEqual([]);
  });

  it("prioritises planned recipe ingredients", () => {
    const a = baseItem({ id: "a", displayName: "Grädde", confidence: 1, verifiedByUser: true });
    const b = baseItem({ id: "b", displayName: "Ost", confidence: 1, verifiedByUser: true });
    const result = buildReconciliationCandidates(
      [b, a],
      {
        plannedRecipeIngredientIds: new Map([["a", ["rec-1"]]]),
        daysLeftByItemId: new Map(),
        dailyConsumptionRate: new Map(),
        priceMinorByItemId: new Map(),
      },
      PINNED,
      15,
    );
    expect(result.map((r) => r.itemId)).toEqual(["a"]);
    expect(result[0]?.reasons).toContainEqual({ kind: "planned_recipe", recipeIds: ["rec-1"] });
  });

  it("flags expiring soon and sorts by urgency", () => {
    const a = baseItem({ id: "a", displayName: "Yoghurt", confidence: 0.5 });
    const b = baseItem({ id: "b", displayName: "Juice", confidence: 0.5 });
    const result = buildReconciliationCandidates(
      [b, a],
      {
        plannedRecipeIngredientIds: new Map(),
        daysLeftByItemId: new Map([
          ["a", 1],
          ["b", 6],
        ]),
        dailyConsumptionRate: new Map(),
        priceMinorByItemId: new Map(),
      },
      PINNED,
    );
    expect(result.map((r) => r.itemId)).toEqual(["a", "b"]);
  });

  it("flags low confidence", () => {
    const item = baseItem({ confidence: 0.3, verifiedByUser: false });
    const result = buildReconciliationCandidates(
      [item],
      { plannedRecipeIngredientIds: new Map(), daysLeftByItemId: new Map(), dailyConsumptionRate: new Map(), priceMinorByItemId: new Map() },
      PINNED,
    );
    expect(result[0]?.reasons).toContainEqual({ kind: "low_confidence", confidence: 0.3 });
  });

  it("suggests depleted when remaining days < 0.5", () => {
    const item = baseItem({ quantity: 0.1 });
    const result = buildReconciliationCandidates(
      [item],
      {
        plannedRecipeIngredientIds: new Map(),
        daysLeftByItemId: new Map(),
        dailyConsumptionRate: new Map([["itm-1", 1]]),
        priceMinorByItemId: new Map(),
      },
      PINNED,
    );
    expect(result[0]?.suggestedAction).toBe("depleted");
  });

  it("caps results at maxItems", () => {
    const items = Array.from({ length: 20 }, (_, i) =>
      baseItem({ id: `itm-${i}`, displayName: `Vara ${String(i).padStart(2, "0")}`, confidence: 0.1 }),
    );
    const result = buildReconciliationCandidates(
      items,
      { plannedRecipeIngredientIds: new Map(), daysLeftByItemId: new Map(), dailyConsumptionRate: new Map(), priceMinorByItemId: new Map() },
      PINNED,
      5,
    );
    expect(result).toHaveLength(5);
  });
});
