import { describe, expect, it } from "vitest";
import {
  DOSSIER_RELATIES,
  RELATIE_INVERS,
  RELATIE_LABEL,
  dossierKortLabel,
  kanKoppelen,
  koppelDossiers,
  koppelingOverzicht,
  ontkoppelDossiers,
  verwijderVerbrokenKoppeling,
} from "./koppeling";
import { maakDossierUitIntakeResultaat } from "./intake";
import type { Dossier, Dossiertype } from "./types";

const T0 = "2026-07-01T10:00:00.000Z";
const T1 = "2026-07-05T10:00:00.000Z";

function maakTestDossier(id: string, dossiertype: Dossiertype = "verkoop-zonder-krediet"): Dossier {
  return maakDossierUitIntakeResultaat(
    { dossiertype, velden: {}, problemen: [] },
    { id, status: "compromis-ontvangen", aangemaakt: T0, aangepast: T0 }
  );
}

describe("relatietabel", () => {
  it("elke relatie heeft een label en een inverse, en de inverse is een involutie", () => {
    for (const relatie of DOSSIER_RELATIES) {
      expect(RELATIE_LABEL[relatie]).toBeTruthy();
      expect(RELATIE_INVERS[RELATIE_INVERS[relatie]]).toBe(relatie);
    }
  });

  it("'verwant' is symmetrisch (zijn eigen inverse)", () => {
    expect(RELATIE_INVERS["verwant"]).toBe("verwant");
  });
});

describe("koppelDossiers", () => {
  it("koppelt symmetrisch: beide zijden dragen de koppeling, elk met de inverse relatie", () => {
    const a = maakTestDossier("a", "nalatenschap");
    const b = maakTestDossier("b");
    const { van, naar } = koppelDossiers(b, a, "volgt-op", T1, "verkoop uit de nalatenschap");

    expect(van.koppelingen).toEqual([
      { dossierId: "a", relatie: "volgt-op", toelichting: "verkoop uit de nalatenschap", aangemaakt: T1 },
    ]);
    expect(naar.koppelingen).toEqual([
      { dossierId: "b", relatie: "gevolgd-door", toelichting: "verkoop uit de nalatenschap", aangemaakt: T1 },
    ]);
    expect(van.aangepast).toBe(T1);
    expect(naar.aangepast).toBe(T1);
    // De invoer wordt niet gemuteerd.
    expect(a.koppelingen).toBeUndefined();
    expect(b.koppelingen).toBeUndefined();
  });

  it("weigert een zelfkoppeling en een tweede koppeling tussen hetzelfde paar (ook een eenzijdig restant)", () => {
    const a = maakTestDossier("a");
    const b = maakTestDossier("b");
    expect(kanKoppelen(a, a).ok).toBe(false);
    expect(() => koppelDossiers(a, a, "verwant", T1)).toThrow();

    const gekoppeld = koppelDossiers(a, b, "heeft-kredietdossier", T1);
    expect(kanKoppelen(gekoppeld.van, gekoppeld.naar).ok).toBe(false);
    expect(() => koppelDossiers(gekoppeld.van, gekoppeld.naar, "verwant", T1)).toThrow();
    // Eenzijdig restant: enkel de tegenzijde draagt nog een koppeling.
    expect(kanKoppelen(a, gekoppeld.naar).ok).toBe(false);
  });
});

describe("ontkoppelDossiers", () => {
  it("verwijdert de koppeling op beide zijden en laat andere koppelingen intact", () => {
    const a = maakTestDossier("a");
    const b = maakTestDossier("b");
    const c = maakTestDossier("c");
    const ab = koppelDossiers(a, b, "verwant", T0);
    const ac = koppelDossiers(ab.van, c, "omvat-deeldossier", T0);

    const { van, naar } = ontkoppelDossiers(ac.van, ab.naar, T1);
    expect(van.koppelingen).toEqual([
      { dossierId: "c", relatie: "omvat-deeldossier", toelichting: undefined, aangemaakt: T0 },
    ]);
    expect(naar.koppelingen).toBeUndefined();
    expect(van.aangepast).toBe(T1);
  });

  it("laat een niet-gekoppeld paar ongewijzigd (ook aangepast)", () => {
    const a = maakTestDossier("a");
    const b = maakTestDossier("b");
    const { van, naar } = ontkoppelDossiers(a, b, T1);
    expect(van).toBe(a);
    expect(naar).toBe(b);
    expect(van.aangepast).toBe(T0);
  });
});

describe("verwijderVerbrokenKoppeling", () => {
  it("verwijdert eenzijdig de koppeling naar een niet meer bestaand dossier", () => {
    const a = maakTestDossier("a");
    const b = maakTestDossier("b");
    const { van } = koppelDossiers(a, b, "verwant", T0);
    const opgeschoond = verwijderVerbrokenKoppeling(van, "b", T1);
    expect(opgeschoond.koppelingen).toBeUndefined();
    expect(opgeschoond.aangepast).toBe(T1);
    // Onbekend id → ongewijzigd.
    expect(verwijderVerbrokenKoppeling(a, "x", T1)).toBe(a);
  });
});

describe("koppelingOverzicht", () => {
  it("lost koppelingen op naar hun doeldossier en markeert verbroken koppelingen", () => {
    const a = maakTestDossier("a");
    const b = maakTestDossier("b", "schenking");
    const { van } = koppelDossiers(a, b, "verwant", T0);

    const metDoel = koppelingOverzicht(van, [van, b]);
    expect(metDoel).toHaveLength(1);
    expect(metDoel[0].label).toBe("is verwant met");
    expect(metDoel[0].doel?.id).toBe("b");
    expect(metDoel[0].doelLabel).toContain("Schenking");

    const verbroken = koppelingOverzicht(van, [van]);
    expect(verbroken[0].doel).toBeUndefined();
    expect(verbroken[0].doelLabel).toContain("bestaat niet meer");
  });
});

describe("dossierKortLabel", () => {
  it("toont referentie, kern (adres of partijen) en dossiertype", () => {
    const verkoop = maakTestDossier("a");
    verkoop.referentie = "2026/123";
    if (verkoop.dossiertype === "verkoop-zonder-krediet") {
      verkoop.goed = { waarde: { adres: "Dorpsstraat 1, Tervuren" }, bron: "compromis" };
    }
    expect(dossierKortLabel(verkoop)).toBe("2026/123 · Dorpsstraat 1, Tervuren · Verkoop zonder krediet");

    const leeg = maakTestDossier("b", "nalatenschap");
    expect(dossierKortLabel(leeg)).toBe("— · Nalatenschap");
  });
});
