"use client";
import { useMemo, useState } from "react";
import {
  bouwNetwerk,
  onderdeelCategorieLabels,
  type DocumentAard,
  type Modeldocument,
  type Modelonderdeel,
  type NetwerkKnoop,
  type NetwerkVerbinding,
} from "@/data/modeldocumenten";

// Kleur per aard van het document.
const AARD_KLEUR: Record<DocumentAard, string> = {
  akte: "#2563eb", // blauw — authentieke akte
  onderhands: "#ea580c", // oranje — onderhands document
};

const BREEDTE = 920;
const HOOGTE = 600;

type AardFilter = "alle" | DocumentAard;

interface Positie {
  x: number;
  y: number;
}

interface Tooltip {
  x: number;
  y: number;
  inhoud: React.ReactNode;
}

/**
 * Deterministische force-directed layout (Fruchterman–Reingold-variant). Geen
 * Math.random — startposities op een cirkel op basis van de index — zodat de
 * layout stabiel en reproduceerbaar is. Pure berekening, gememoïseerd door de
 * aanroeper.
 */
function berekenLayout(
  knopen: NetwerkKnoop[],
  verbindingen: NetwerkVerbinding[],
): Map<string, Positie> {
  const n = knopen.length;
  const pos = new Map<string, Positie>();
  if (n === 0) return pos;

  knopen.forEach((k, i) => {
    const hoek = (2 * Math.PI * i) / n;
    pos.set(k.id, {
      x: BREEDTE / 2 + Math.cos(hoek) * BREEDTE * 0.32,
      y: HOOGTE / 2 + Math.sin(hoek) * HOOGTE * 0.32,
    });
  });

  const k = Math.sqrt((BREEDTE * HOOGTE) / n) * 0.7;
  const randen = verbindingen.map((v) => [v.bron, v.doel] as const);
  const iteraties = Math.min(400, 120 + n * 6);
  let temp = BREEDTE * 0.12;

  for (let it = 0; it < iteraties; it++) {
    const disp = new Map<string, Positie>(knopen.map((kn) => [kn.id, { x: 0, y: 0 }]));

    // Afstoting tussen alle paren.
    for (let i = 0; i < n; i++) {
      for (let j = i + 1; j < n; j++) {
        const a = pos.get(knopen[i].id)!;
        const b = pos.get(knopen[j].id)!;
        let dx = a.x - b.x;
        let dy = a.y - b.y;
        let d = Math.hypot(dx, dy);
        if (d < 0.01) {
          dx = (i - j) * 0.01 + 0.01;
          dy = 0.01;
          d = Math.hypot(dx, dy);
        }
        const f = (k * k) / d;
        const ux = dx / d;
        const uy = dy / d;
        const di = disp.get(knopen[i].id)!;
        const dj = disp.get(knopen[j].id)!;
        di.x += ux * f;
        di.y += uy * f;
        dj.x -= ux * f;
        dj.y -= uy * f;
      }
    }

    // Aantrekking langs de verbindingen.
    for (const [s, t] of randen) {
      const a = pos.get(s);
      const b = pos.get(t);
      if (!a || !b) continue;
      const dx = a.x - b.x;
      const dy = a.y - b.y;
      const d = Math.hypot(dx, dy) || 0.01;
      const f = (d * d) / k;
      const ux = dx / d;
      const uy = dy / d;
      const ds = disp.get(s)!;
      const dt = disp.get(t)!;
      ds.x -= ux * f;
      ds.y -= uy * f;
      dt.x += ux * f;
      dt.y += uy * f;
    }

    // Lichte zwaartekracht naar het midden, houdt losse clusters samen.
    for (const kn of knopen) {
      const p = pos.get(kn.id)!;
      const d = disp.get(kn.id)!;
      d.x += (BREEDTE / 2 - p.x) * 0.012;
      d.y += (HOOGTE / 2 - p.y) * 0.012;
    }

    // Verplaatsing toepassen, begrensd door de temperatuur (cooling).
    for (const kn of knopen) {
      const d = disp.get(kn.id)!;
      const p = pos.get(kn.id)!;
      const dl = Math.hypot(d.x, d.y) || 0.01;
      p.x += (d.x / dl) * Math.min(dl, temp);
      p.y += (d.y / dl) * Math.min(dl, temp);
      p.x = Math.max(24, Math.min(BREEDTE - 24, p.x));
      p.y = Math.max(24, Math.min(HOOGTE - 24, p.y));
    }
    temp *= 0.95;
  }

  return pos;
}

export function OnderdelenNetwerk({
  alleModellen,
  alleOnderdelen,
}: {
  alleModellen: Modeldocument[];
  alleOnderdelen: Modelonderdeel[];
}) {
  const [aardFilter, setAardFilter] = useState<AardFilter>("alle");
  const [toonLabels, setToonLabels] = useState(false);
  const [actief, setActief] = useState<string | null>(null); // gemarkeerde knoop-id
  const [tooltip, setTooltip] = useState<Tooltip | null>(null);

  const netwerk = useMemo(
    () => bouwNetwerk(alleModellen, alleOnderdelen),
    [alleModellen, alleOnderdelen],
  );
  const posities = useMemo(
    () => berekenLayout(netwerk.knopen, netwerk.verbindingen),
    [netwerk],
  );

  const zichtbareVerbindingen = useMemo(
    () =>
      aardFilter === "alle"
        ? netwerk.verbindingen
        : netwerk.verbindingen.filter((v) => v.aard === aardFilter),
    [netwerk.verbindingen, aardFilter],
  );

  // Knopen die door de huidige aard-filter nog een verbinding hebben (voor faden).
  const verbondenIds = useMemo(() => {
    const set = new Set<string>();
    for (const v of zichtbareVerbindingen) {
      set.add(v.bron);
      set.add(v.doel);
    }
    return set;
  }, [zichtbareVerbindingen]);

  // Buren van de actieve knoop (voor markeren).
  const buurIds = useMemo(() => {
    const set = new Set<string>();
    if (!actief) return set;
    for (const v of netwerk.verbindingen) {
      if (v.bron === actief) set.add(v.doel);
      if (v.doel === actief) set.add(v.bron);
    }
    return set;
  }, [actief, netwerk.verbindingen]);

  function knoopRadius(k: NetwerkKnoop): number {
    return 5 + Math.min(11, (k.gebruik - 1) * 2.2);
  }

  function isGedimd(id: string): boolean {
    if (actief) return id !== actief && !buurIds.has(id);
    if (aardFilter !== "alle") return !verbondenIds.has(id);
    return false;
  }

  function knoopTooltip(k: NetwerkKnoop): React.ReactNode {
    const akten = k.modellen.filter((m) => m.aard === "akte");
    const onderhands = k.modellen.filter((m) => m.aard === "onderhands");
    return (
      <div className="space-y-1">
        <p className="font-semibold text-slate-100">{k.titel}</p>
        <p className="text-slate-400">{onderdeelCategorieLabels[k.categorie]}</p>
        <p className="text-slate-300">
          In {k.gebruik} document{k.gebruik > 1 ? "en" : ""}:
        </p>
        <ul className="space-y-0.5">
          {akten.map((m) => (
            <li key={m.id} className="flex items-center gap-1.5">
              <span className="inline-block size-2 rounded-full" style={{ background: AARD_KLEUR.akte }} />
              {m.titel}
            </li>
          ))}
          {onderhands.map((m) => (
            <li key={m.id} className="flex items-center gap-1.5">
              <span
                className="inline-block size-2 rounded-full"
                style={{ background: AARD_KLEUR.onderhands }}
              />
              {m.titel}
            </li>
          ))}
        </ul>
      </div>
    );
  }

  function plaatsTooltip(e: React.MouseEvent, inhoud: React.ReactNode) {
    const rect = (e.currentTarget.closest("svg") as SVGSVGElement).getBoundingClientRect();
    setTooltip({
      x: e.clientX - rect.left,
      y: e.clientY - rect.top,
      inhoud,
    });
  }

  if (netwerk.knopen.length === 0) {
    return <p className="text-sm text-slate-400">Nog geen modeldocumenten om te verbinden.</p>;
  }

  return (
    <div className="space-y-3">
      <div className="flex flex-wrap items-center gap-3">
        <div className="inline-flex rounded-lg border border-slate-200 overflow-hidden">
          {(
            [
              ["alle", "Alle documenten"],
              ["akte", "Authentieke akten"],
              ["onderhands", "Onderhandse documenten"],
            ] as [AardFilter, string][]
          ).map(([id, label]) => (
            <button
              key={id}
              onClick={() => setAardFilter(id)}
              className={`text-sm px-3 py-1.5 transition-colors ${
                aardFilter === id
                  ? "bg-slate-800 text-white font-medium"
                  : "bg-white text-slate-500 hover:text-slate-700"
              }`}
            >
              {label}
            </button>
          ))}
        </div>
        <label className="flex items-center gap-1.5 text-sm text-slate-600">
          <input
            type="checkbox"
            checked={toonLabels}
            onChange={(e) => setToonLabels(e.target.checked)}
            className="size-4 accent-brand-600"
          />
          Labels tonen
        </label>
        <div className="flex items-center gap-3 text-xs text-slate-500 ml-auto">
          <span className="flex items-center gap-1.5">
            <span className="inline-block w-4 h-0.5 rounded" style={{ background: AARD_KLEUR.akte }} />
            authentieke akte
          </span>
          <span className="flex items-center gap-1.5">
            <span
              className="inline-block w-4 h-0.5 rounded"
              style={{ background: AARD_KLEUR.onderhands }}
            />
            onderhands document
          </span>
        </div>
      </div>

      <p className="text-xs text-slate-400">
        Elke stip is een modelonderdeel (grootte = aantal documenten waarin het voorkomt); elke lijn
        is een modeldocument dat zijn onderdelen verbindt. Beweeg over een stip of lijn voor details;
        klik op een stip om zijn documenten te isoleren.
      </p>

      <div className="relative bg-slate-50 border border-slate-200 rounded-xl overflow-hidden">
        <svg
          viewBox={`0 0 ${BREEDTE} ${HOOGTE}`}
          className="w-full h-auto"
          onClick={() => setActief(null)}
          onMouseLeave={() => setTooltip(null)}
        >
          {/* Verbindingen */}
          <g>
            {zichtbareVerbindingen.map((v, i) => {
              const a = posities.get(v.bron);
              const b = posities.get(v.doel);
              if (!a || !b) return null;
              const betrokken =
                !actief || v.bron === actief || v.doel === actief;
              return (
                <line
                  key={`${v.modelId}-${i}`}
                  x1={a.x}
                  y1={a.y}
                  x2={b.x}
                  y2={b.y}
                  stroke={AARD_KLEUR[v.aard]}
                  strokeWidth={betrokken ? 2 : 1}
                  strokeOpacity={betrokken ? 0.6 : 0.08}
                  strokeLinecap="round"
                  onMouseEnter={(e) =>
                    plaatsTooltip(
                      e,
                      <div className="space-y-0.5">
                        <p className="font-semibold text-slate-100">{v.titel}</p>
                        <p className="text-slate-300">{v.akteType}</p>
                        <p style={{ color: AARD_KLEUR[v.aard] }}>
                          {v.aard === "akte" ? "Authentieke akte" : "Onderhands document"}
                        </p>
                      </div>,
                    )
                  }
                  onMouseMove={(e) =>
                    plaatsTooltip(
                      e,
                      <div className="space-y-0.5">
                        <p className="font-semibold text-slate-100">{v.titel}</p>
                        <p className="text-slate-300">{v.akteType}</p>
                        <p style={{ color: AARD_KLEUR[v.aard] }}>
                          {v.aard === "akte" ? "Authentieke akte" : "Onderhands document"}
                        </p>
                      </div>,
                    )
                  }
                  onMouseLeave={() => setTooltip(null)}
                />
              );
            })}
          </g>

          {/* Knopen */}
          <g>
            {netwerk.knopen.map((kn) => {
              const p = posities.get(kn.id);
              if (!p) return null;
              const r = knoopRadius(kn);
              const gedimd = isGedimd(kn.id);
              const isActief = actief === kn.id;
              return (
                <g
                  key={kn.id}
                  transform={`translate(${p.x},${p.y})`}
                  style={{ cursor: "pointer", opacity: gedimd ? 0.2 : 1 }}
                  onClick={(e) => {
                    e.stopPropagation();
                    setActief((huidig) => (huidig === kn.id ? null : kn.id));
                  }}
                  onMouseEnter={(e) => plaatsTooltip(e, knoopTooltip(kn))}
                  onMouseMove={(e) => plaatsTooltip(e, knoopTooltip(kn))}
                  onMouseLeave={() => setTooltip(null)}
                >
                  <circle
                    r={r}
                    fill="#ffffff"
                    stroke={isActief ? "#0f766e" : "#475569"}
                    strokeWidth={isActief ? 3 : 1.5}
                  />
                  <circle r={Math.max(2, r - 3)} fill="#64748b" fillOpacity={isActief ? 0.9 : 0.55} />
                  {(toonLabels || isActief || kn.gebruik >= 3) && (
                    <text
                      x={0}
                      y={r + 11}
                      textAnchor="middle"
                      className="pointer-events-none"
                      fontSize={11}
                      fill="#334155"
                    >
                      {kn.titel.length > 28 ? kn.titel.slice(0, 27) + "…" : kn.titel}
                    </text>
                  )}
                </g>
              );
            })}
          </g>
        </svg>

        {tooltip && (
          <div
            className="absolute z-10 pointer-events-none max-w-xs text-xs bg-slate-900 text-slate-200 rounded-lg px-3 py-2 shadow-lg"
            style={{
              left: Math.min(tooltip.x + 12, BREEDTE - 240),
              top: tooltip.y + 12,
            }}
          >
            {tooltip.inhoud}
          </div>
        )}
      </div>
    </div>
  );
}
