import { describe, it, expect } from "vitest";
import {
  waarnemingen,
  effectieveWaarneming,
  maakVeldUitWaarnemingen,
  isTegenstrijdig,
  veldTegenstrijdigheid,
  berekenTegenstrijdigheden,
  kiesPrimaireBron,
} from "./tegenstrijdigheden";
import { euro } from "@/lib/format";
import { maakVeld, type Dossier, type Veld } from "./types";

function maakDossier(overschrijf: Partial<Dossier> = {}): Dossier {
  return {
    id: "d1",
    dossiertype: "verkoop-zonder-krediet",
    status: "compromis-ontvangen",
    partijen: maakVeld([{ naam: "Janssens", rol: "verkoper" }], "compromis"),
    goed: maakVeld({ adres: "Kerkstraat 1" }, "eigendomstitel"),
    prijs: maakVeld(300000, "compromis"),
    ontbrekendeStukken: [],
    tegenstrijdigheden: [],
    aangemaakt: "2026-01-01T00:00:00.000Z",
    aangepast: "2026-01-01T00:00:00.000Z",
    ...overschrijf,
  } as Dossier;
}

describe("waarnemingen", () => {
  it("geeft de primaire waarneming plus de alternatieven terug", () => {
    const veld: Veld<number> = {
      waarde: 300000,
      bron: "compromis",
      alternatieven: [{ waarde: 320000, bron: "eigendomstitel" }],
    };
    expect(waarnemingen(veld)).toHaveLength(2);
    expect(waarnemingen(veld)[0].waarde).toBe(300000);
  });
});

describe("effectieveWaarneming", () => {
  it("kiest de waarneming met het hoogste brongezag (laagste prioriteitsgetal)", () => {
    const veld: Veld<number> = {
      waarde: 300000,
      bron: "compromis", // prioriteit 3
      alternatieven: [{ waarde: 320000, bron: "eigendomstitel" }], // prioriteit 1
    };
    const eff = effectieveWaarneming(veld);
    expect(eff.waarde).toBe(320000);
    expect(eff.bron).toBe("eigendomstitel");
  });
});

describe("maakVeldUitWaarnemingen", () => {
  it("zet de gezaghebbendste waarneming als primaire waarde en bewaart afwijkende als alternatief", () => {
    const veld = maakVeldUitWaarnemingen(
      [
        { waarde: 300000, bron: "compromis" },
        { waarde: 320000, bron: "eigendomstitel" },
      ],
      euro
    );
    expect(veld.waarde).toBe(320000);
    expect(veld.bron).toBe("eigendomstitel");
    expect(veld.alternatieven).toHaveLength(1);
    expect(veld.alternatieven?.[0].waarde).toBe(300000);
  });

  it("bewaart geen alternatief wanneer alle waarnemingen overeenstemmen", () => {
    const veld = maakVeldUitWaarnemingen(
      [
        { waarde: 300000, bron: "compromis" },
        { waarde: 300000, bron: "eigendomstitel" },
      ],
      euro
    );
    expect(veld.waarde).toBe(300000);
    expect(veld.bron).toBe("eigendomstitel");
    expect(veld.alternatieven).toBeUndefined();
  });

  it("gooit een fout bij een lege lijst waarnemingen", () => {
    expect(() => maakVeldUitWaarnemingen([])).toThrow();
  });
});

describe("veldTegenstrijdigheid / isTegenstrijdig", () => {
  it("geeft null wanneer er maar één waarneming is", () => {
    expect(veldTegenstrijdigheid("Prijs", maakVeld(300000, "compromis"), euro)).toBeNull();
    expect(isTegenstrijdig(maakVeld(300000, "compromis"), euro)).toBe(false);
  });

  it("somt de afwijkende waarden op, hoogste gezag eerst", () => {
    const veld: Veld<number> = {
      waarde: 300000,
      bron: "compromis",
      alternatieven: [{ waarde: 320000, bron: "eigendomstitel" }],
    };
    const t = veldTegenstrijdigheid("Verkoopprijs", veld, euro);
    expect(t).not.toBeNull();
    expect(t?.veld).toBe("Verkoopprijs");
    expect(t?.waarden.map((w) => w.bron)).toEqual(["eigendomstitel", "compromis"]);
    expect(isTegenstrijdig(veld, euro)).toBe(true);
  });

  it("ontdubbelt identieke waarden uit verschillende bronnen", () => {
    const veld: Veld<number> = {
      waarde: 300000,
      bron: "compromis",
      alternatieven: [{ waarde: 300000, bron: "eigendomstitel" }],
    };
    expect(veldTegenstrijdigheid("Prijs", veld, euro)).toBeNull();
  });
});

describe("berekenTegenstrijdigheden", () => {
  it("detecteert een tegenstrijdige verkoopprijs tussen bronnen", () => {
    const dossier = maakDossier({
      prijs: { waarde: 300000, bron: "compromis", alternatieven: [{ waarde: 320000, bron: "eigendomstitel" }] },
    });
    const conflicten = berekenTegenstrijdigheden(dossier);
    expect(conflicten).toHaveLength(1);
    expect(conflicten[0].veld).toBe("Verkoopprijs");
    expect(conflicten[0].opgelost).toBe(false);
  });

  it("geeft geen conflicten bij eenduidige velden", () => {
    expect(berekenTegenstrijdigheden(maakDossier())).toEqual([]);
  });

  it("behoudt een eerder als opgelost gemarkeerde tegenstrijdigheid", () => {
    const dossier = maakDossier({
      prijs: { waarde: 300000, bron: "compromis", alternatieven: [{ waarde: 320000, bron: "eigendomstitel" }] },
      tegenstrijdigheden: [
        { veld: "Verkoopprijs", waarden: [], opgelost: true },
      ],
    });
    const conflicten = berekenTegenstrijdigheden(dossier);
    expect(conflicten).toHaveLength(1);
    expect(conflicten[0].opgelost).toBe(true);
  });

  it("voorziet elke tegenstrijdigheid van een stabiele veldsleutel", () => {
    const dossier = maakDossier({
      prijs: { waarde: 300000, bron: "compromis", alternatieven: [{ waarde: 320000, bron: "eigendomstitel" }] },
    });
    expect(berekenTegenstrijdigheden(dossier)[0].veldSleutel).toBe("prijs");
  });
});

describe("kiesPrimaireBron", () => {
  it("maakt de gekozen bron primair en behoudt de rest als alternatief", () => {
    const veld: Veld<number> = {
      waarde: 320000,
      bron: "eigendomstitel",
      alternatieven: [{ waarde: 300000, bron: "compromis" }],
    };
    const gekozen = kiesPrimaireBron(veld, "compromis");
    expect(gekozen.waarde).toBe(300000);
    expect(gekozen.bron).toBe("compromis");
    expect(gekozen.alternatieven).toEqual([{ waarde: 320000, bron: "eigendomstitel" }]);
  });

  it("laat het veld ongewijzigd bij een onbekende bron", () => {
    const veld: Veld<number> = { waarde: 320000, bron: "eigendomstitel" };
    expect(kiesPrimaireBron(veld, "compromis")).toBe(veld);
  });
});
