import { describe, it, expect } from "vitest";
import {
  signalenUitGebruikslog,
  signalenUitAudit,
  bouwVerbeterkandidaten,
  verbeterkandidatenUitErvaring,
} from "./verbeterlus";
import type { GebruikslogEvent } from "@/lib/gebruikslog";
import type { AuditBevinding } from "@/data/modeldocumenten";

const NU = new Date("2026-07-08T12:00:00Z").getTime();
const vandaag = "2026-07-08";

describe("signalenUitGebruikslog", () => {
  it("mapt bekende gebruikslog-soorten en negeert onbekende", () => {
    const events: GebruikslogEvent[] = [
      { type: "onbekend_modeldocument", waarde: "verkoop-op-lijfrente", tijdstip: vandaag },
      { type: "connector_fout", waarde: "kadaster", tijdstip: vandaag },
      { type: "iets_onbekends" as GebruikslogEvent["type"], waarde: "x", tijdstip: vandaag },
    ];
    const signalen = signalenUitGebruikslog(events);
    expect(signalen).toHaveLength(2);
    expect(signalen[0].bron).toBe("gebruikslog");
    expect(signalen[0].onderwerp).toBe("verkoop-op-lijfrente");
  });
});

describe("signalenUitAudit", () => {
  it("weegt fouten dubbel t.o.v. waarschuwingen", () => {
    const bevindingen: AuditBevinding[] = [
      { ernst: "fout", code: "rol-mapping-ontbreekt", onderwerp: "m1", sleutel: "verkoopakte - lijfrente", omschrijving: "" },
      { ernst: "waarschuwing", code: "tegenhanger-ontbreekt", onderwerp: "m2", omschrijving: "" },
    ];
    const signalen = signalenUitAudit(bevindingen, vandaag);
    // rol-mapping ernst 5 × 2 (fout) = 10; tegenhanger ernst 3 × 1 = 3
    expect(signalen[0].gewicht).toBe(10);
    expect(signalen[1].gewicht).toBe(3);
    expect(signalen[0].onderwerp).toBe("verkoopakte - lijfrente"); // sleutel wint van onderwerp
  });
});

describe("bouwVerbeterkandidaten", () => {
  it("clustert per (soort, onderwerp) en routeert naar het juiste kanaal", () => {
    const signalen = signalenUitGebruikslog([
      { type: "onbekend_modeldocument", waarde: "verkoop-op-lijfrente", tijdstip: vandaag },
      { type: "onbekend_modeldocument", waarde: "verkoop-op-lijfrente", tijdstip: vandaag },
      { type: "connector_fout", waarde: "kadaster", tijdstip: vandaag },
    ]);
    const kandidaten = bouwVerbeterkandidaten(signalen, { nu: NU });
    expect(kandidaten).toHaveLength(2);
    const model = kandidaten.find((k) => k.sleutel.includes("verkoop-op-lijfrente"))!;
    expect(model.kanaal).toBe("bibliotheek");
    expect(model.signalen).toHaveLength(2);
    const connector = kandidaten.find((k) => k.sleutel.includes("kadaster"))!;
    expect(connector.kanaal).toBe("code");
    expect(connector.categorie).toBe("integratie");
  });

  it("rangschikt op score: vaker + ernstiger + recenter komt eerst", () => {
    const signalen = signalenUitGebruikslog([
      // 3× hetzelfde onbekende model (ernst 4) → hoge score
      { type: "onbekend_modeldocument", waarde: "veel-gevraagd", tijdstip: vandaag },
      { type: "onbekend_modeldocument", waarde: "veel-gevraagd", tijdstip: vandaag },
      { type: "onbekend_modeldocument", waarde: "veel-gevraagd", tijdstip: vandaag },
      // 1× een parameterprobleem (ernst 2) → lage score
      { type: "onbekende_parameter", waarde: "iets", tijdstip: vandaag },
    ]);
    const kandidaten = bouwVerbeterkandidaten(signalen, { nu: NU });
    expect(kandidaten[0].sleutel).toContain("veel-gevraagd");
    expect(kandidaten[0].prioriteit).toBe("hoog");
    expect(kandidaten[0].score).toBeGreaterThan(kandidaten[1].score);
  });

  it("laat recentheid meewegen: een oud signaal scoort lager dan een vers", () => {
    const oud = signalenUitGebruikslog([{ type: "onbekend_modeldocument", waarde: "oud", tijdstip: "2026-05-01" }]);
    const vers = signalenUitGebruikslog([{ type: "onbekend_modeldocument", waarde: "vers", tijdstip: vandaag }]);
    const [kOud] = bouwVerbeterkandidaten(oud, { nu: NU });
    const [kVers] = bouwVerbeterkandidaten(vers, { nu: NU });
    expect(kVers.score).toBeGreaterThan(kOud.score);
  });

  it("past anti-terugkoppeling toe: reeds ingediende sleutels vallen weg", () => {
    const signalen = signalenUitGebruikslog([
      { type: "onbekend_modeldocument", waarde: "al-ingediend", tijdstip: vandaag },
      { type: "onbekend_modeldocument", waarde: "nieuw", tijdstip: vandaag },
    ]);
    const eerste = bouwVerbeterkandidaten(signalen, { nu: NU });
    const reedsIngediend = new Set(eerste.filter((k) => k.sleutel.includes("al-ingediend")).map((k) => k.sleutel));
    const tweede = bouwVerbeterkandidaten(signalen, { nu: NU, reedsIngediend });
    expect(tweede.map((k) => k.sleutel)).toEqual([expect.stringContaining("nieuw")]);
  });
});

describe("verbeterkandidatenUitErvaring", () => {
  it("combineert gebruikslog en audit tot één gerangschikte lijst", () => {
    const kandidaten = verbeterkandidatenUitErvaring({
      gebruikslog: [{ type: "onbekende_parameter", waarde: "naam_x", tijdstip: vandaag }],
      auditBevindingen: [
        { ernst: "fout", code: "rol-mapping-ontbreekt", onderwerp: "m1", sleutel: "verkoopakte - lijfrente", omschrijving: "" },
      ],
      auditDatum: vandaag,
      nu: NU,
    });
    const kanalen = new Set(kandidaten.map((k) => k.kanaal));
    expect(kanalen.has("bibliotheek")).toBe(true);
    expect(kanalen.has("code")).toBe(true);
    // de fout (rol-mapping, gewicht 10) staat vóór de lichte parameterwaarschuwing
    expect(kandidaten[0].sleutel).toContain("verkoopakte - lijfrente");
  });
});
