import { PolicyMatcherService } from "./policy-matcher.service";
import type { PrismaService } from "../prisma/prisma.service";
import type { ParsedPolicy } from "./parsers/policy-parser";

function parsed(over: Partial<ParsedPolicy> = {}): ParsedPolicy {
  return {
    provider: "GMX",
    policyNumber: null,
    insuredName: null,
    notes: [],
    coverages: [],
    vehicles: [],
    drivers: [],
    ...over,
  } as unknown as ParsedPolicy;
}

function prismaStub(policies: unknown[], customers: { id: string; name: string }[]) {
  const findManyPolicy = jest.fn().mockResolvedValue(policies);
  const findManyCustomer = jest.fn().mockResolvedValue(customers);
  return {
    prisma: {
      policy: { findMany: findManyPolicy },
      customer: { findMany: findManyCustomer },
    } as unknown as PrismaService,
    findManyPolicy,
    findManyCustomer,
  };
}

const BOOK = [
  { id: "cust-1", name: "WAGONER, PAMELA" },
  { id: "cust-2", name: "SMITH, JOHN" },
];

describe("PolicyMatcherService name suggestions", () => {
  it("suggests a customer when the policy number is new", async () => {
    const { prisma } = prismaStub([], BOOK);
    const svc = new PolicyMatcherService(prisma);

    const r = await svc.match(
      parsed({ policyNumber: "P-999", insuredName: "PAMELA DENISE WAGONER" } as never),
    );

    expect(r.customerSuggestions).toEqual([
      expect.objectContaining({ customerId: "cust-1", tier: "PARTIAL" }),
    ]);
    // The suggestion is surfaced, never applied.
    expect(r.customerId).toBeNull();
    expect(r.confident).toBe(false);
    expect(r.note).toContain("posibles clientes por nombre: WAGONER, PAMELA");
  });

  it("suggests when the policy number could not be read at all", async () => {
    const { prisma } = prismaStub([], BOOK);
    const svc = new PolicyMatcherService(prisma);

    const r = await svc.match(parsed({ insuredName: "PAMELA WAGONER" } as never));

    expect(r.customerSuggestions[0]).toMatchObject({ customerId: "cust-1", tier: "EXACT" });
    expect(r.customerId).toBeNull();
    expect(r.note).toBe(
      "no se pudo leer el número de póliza; posible cliente por nombre: WAGONER, PAMELA",
    );
  });

  it("does not touch the book when the policy number hits", async () => {
    const { prisma, findManyCustomer } = prismaStub(
      [
        {
          id: "pol-1",
          policyNumber: "P-1",
          customerId: "cust-2",
          customer: { name: "SMITH, JOHN" },
        },
      ],
      BOOK,
    );
    const svc = new PolicyMatcherService(prisma);

    const r = await svc.match(
      parsed({ policyNumber: "P-1", insuredName: "PAMELA WAGONER" } as never),
    );

    expect(r.confident).toBe(true);
    expect(r.customerId).toBe("cust-2");
    expect(r.customerSuggestions).toEqual([]);
    expect(findManyCustomer).not.toHaveBeenCalled();
  });

  it("reads the customer book once across a batch", async () => {
    const { prisma, findManyCustomer } = prismaStub([], BOOK);
    const svc = new PolicyMatcherService(prisma);

    await svc.match(parsed({ policyNumber: "A", insuredName: "PAMELA WAGONER" } as never));
    await svc.match(parsed({ policyNumber: "B", insuredName: "JOHN SMITH" } as never));

    expect(findManyCustomer).toHaveBeenCalledTimes(1);
  });
});
