"use client";
import { useState, useEffect, useCallback } from "react";
import { getDb, type GebruikersWetOpslag, type ActualiteitStatus, type VolledigeTekstOpslag } from "@/lib/db/regelgeving-db";
import { wetten, type Annotatie, type GebruikersWet, type Artikel, type Toepassingsgebied, type Thema } from "@/data/regelgeving";

export type { ActualiteitStatus };

export function useRegelgevingStorage() {
  const [annotaties, setAnnotaties] = useState<Annotatie[]>([]);
  const [gebruikersWetten, setGebruikersWetten] = useState<GebruikersWet[]>([]);
  const [bladwijzers, setBladwijzers] = useState<Set<string>>(new Set());
  const [actualiteitStatussen, setActualiteitStatussen] = useState<Map<string, ActualiteitStatus>>(new Map());
  const [volledigeTeksten, setVolledigeTeksten] = useState<Map<string, string>>(new Map());
  const [geladen, setGeladen] = useState(false);

  useEffect(() => {
    async function laadAlles() {
      const db = await getDb();
      const [ann, wetten, bwArr, statussen, teksten] = await Promise.all([
        db.getAll("annotaties"),
        db.getAll("gebruikersWetten"),
        db.getAll("bladwijzers"),
        db.getAll("actualiteitStatus"),
        db.getAll("volledigeTeksten"),
      ]);
      setAnnotaties(ann);
      setGebruikersWetten(wetten.map(dbWetNaarGebruikersWet));
      setBladwijzers(new Set(bwArr.map((b) => b.artikelId)));
      setActualiteitStatussen(new Map(statussen.map((s) => [s.wetId, s])));
      setVolledigeTeksten(new Map(teksten.map((t) => [t.sleutel, t.tekst])));
      setGeladen(true);
    }
    laadAlles();
  }, []);

  // ── Annotaties ──────────────────────────────────────────────────
  const addAnnotatie = useCallback(async (wetId: string, artikelId: string, tekst: string) => {
    const ny: Annotatie = {
      id: crypto.randomUUID(),
      wetId,
      artikelId,
      tekst,
      aangemaakt: new Date().toISOString(),
      aangepast: new Date().toISOString(),
    };
    const db = await getDb();
    await db.put("annotaties", ny);
    setAnnotaties((prev) => [...prev, ny]);
  }, []);

  const updateAnnotatie = useCallback(async (id: string, tekst: string) => {
    setAnnotaties((prev) => {
      const updated = prev.map((a) =>
        a.id === id ? { ...a, tekst, aangepast: new Date().toISOString() } : a
      );
      getDb().then((db) => {
        const found = updated.find((a) => a.id === id);
        if (found) db.put("annotaties", found);
      });
      return updated;
    });
  }, []);

  const deleteAnnotatie = useCallback(async (id: string) => {
    const db = await getDb();
    await db.delete("annotaties", id);
    setAnnotaties((prev) => prev.filter((a) => a.id !== id));
  }, []);

  const getAnnotatiesVoorArtikel = useCallback(
    (wetId: string, artikelId: string): Annotatie[] =>
      annotaties.filter((a) => a.wetId === wetId && a.artikelId === artikelId),
    [annotaties]
  );

  // ── Volledige teksten ────────────────────────────────────────────
  const setVolledigeTekst = useCallback(async (wetId: string, artikelId: string, tekst: string) => {
    const sleutel = `${wetId}:${artikelId}`;
    const record: VolledigeTekstOpslag = {
      sleutel,
      wetId,
      artikelId,
      tekst,
      aangepast: new Date().toISOString(),
    };
    const db = await getDb();
    await db.put("volledigeTeksten", record);
    setVolledigeTeksten((prev) => new Map(prev).set(sleutel, tekst));
  }, []);

  const getVolledigeTekst = useCallback(
    (wetId: string, artikelId: string): string | undefined => {
      // IndexedDB heeft voorrang (gebruikersedit), daarna statische data
      const opgeslagen = volledigeTeksten.get(`${wetId}:${artikelId}`);
      if (opgeslagen !== undefined) return opgeslagen;
      const wet = wetten.find((w) => w.id === wetId);
      return wet?.artikels.find((a) => a.id === artikelId)?.volledigeTekst;
    },
    [volledigeTeksten]
  );

  // ── Gebruikerswetten ─────────────────────────────────────────────
  const addGebruikersWet = useCallback(
    async (data: Omit<GebruikersWet, "id" | "isGebruiker" | "artikels">) => {
      const ny: GebruikersWetOpslag = {
        id: crypto.randomUUID(),
        ...data,
        artikels: [],
        aangemaakt: new Date().toISOString(),
        aangepast: new Date().toISOString(),
      };
      const db = await getDb();
      await db.put("gebruikersWetten", ny);
      setGebruikersWetten((prev) => [...prev, dbWetNaarGebruikersWet(ny)]);
    },
    []
  );

  const addArtikelAanGebruikersWet = useCallback(async (wetId: string, artikel: Omit<Artikel, "id">) => {
    const db = await getDb();
    const wet = await db.get("gebruikersWetten", wetId);
    if (!wet) return;
    const nyArtikel = { ...artikel, id: crypto.randomUUID() };
    const updated = { ...wet, artikels: [...wet.artikels, nyArtikel], aangepast: new Date().toISOString() };
    await db.put("gebruikersWetten", updated);
    setGebruikersWetten((prev) =>
      prev.map((w) => (w.id === wetId ? dbWetNaarGebruikersWet(updated) : w))
    );
  }, []);

  const deleteGebruikersWet = useCallback(async (id: string) => {
    const db = await getDb();
    await db.delete("gebruikersWetten", id);
    // Verwijder bijhorende annotaties en teksten
    const tx = db.transaction(["annotaties", "volledigeTeksten"], "readwrite");
    const allAnn = await tx.objectStore("annotaties").getAll();
    await Promise.all(allAnn.filter((a) => a.wetId === id).map((a) => tx.objectStore("annotaties").delete(a.id)));
    const allTxt = await tx.objectStore("volledigeTeksten").index("by-wet").getAll(id);
    await Promise.all(allTxt.map((t) => tx.objectStore("volledigeTeksten").delete(t.sleutel)));
    await tx.done;
    setGebruikersWetten((prev) => prev.filter((w) => w.id !== id));
    setAnnotaties((prev) => prev.filter((a) => a.wetId !== id));
    setVolledigeTeksten((prev) => {
      const next = new Map(prev);
      for (const [k] of next) {
        if (k.startsWith(`${id}:`)) next.delete(k);
      }
      return next;
    });
  }, []);

  // ── Bladwijzers ──────────────────────────────────────────────────
  const toggleBladwijzer = useCallback(async (artikelId: string) => {
    const db = await getDb();
    setBladwijzers((prev) => {
      const next = new Set(prev);
      if (next.has(artikelId)) {
        next.delete(artikelId);
        db.delete("bladwijzers", artikelId);
      } else {
        next.add(artikelId);
        db.put("bladwijzers", { artikelId });
      }
      return next;
    });
  }, []);

  const isBladwijzer = useCallback(
    (artikelId: string) => bladwijzers.has(artikelId),
    [bladwijzers]
  );

  // ── Actualiteitsstatus ───────────────────────────────────────────
  const slaActualiteitOp = useCallback(async (status: ActualiteitStatus) => {
    const db = await getDb();
    await db.put("actualiteitStatus", status);
    setActualiteitStatussen((prev) => new Map(prev).set(status.wetId, status));
  }, []);

  const getActualiteitStatus = useCallback(
    (wetId: string): ActualiteitStatus | undefined => actualiteitStatussen.get(wetId),
    [actualiteitStatussen]
  );

  return {
    geladen,
    annotaties,
    addAnnotatie,
    updateAnnotatie,
    deleteAnnotatie,
    getAnnotatiesVoorArtikel,
    volledigeTeksten,
    setVolledigeTekst,
    getVolledigeTekst,
    gebruikersWetten,
    addGebruikersWet,
    addArtikelAanGebruikersWet,
    deleteGebruikersWet,
    bladwijzers,
    toggleBladwijzer,
    isBladwijzer,
    actualiteitStatussen,
    slaActualiteitOp,
    getActualiteitStatus,
  };
}

function dbWetNaarGebruikersWet(w: GebruikersWetOpslag): GebruikersWet {
  return { ...w, isGebruiker: true };
}
