// ── Werkdossier-sessies: elke Word-generatie 24 uur raadpleegbaar/bijwerkbaar ─
// Wanneer een agent of gebruiker een .docx laat genereren (werkdossier of los
// ontwerpdocument), bewaart deze module de VOLLEDIGE generatie-invoer 24 uur
// onder een ongokbaar token. Zo kan iedereen — mens via /werkdossiers, agent
// via MCP — het dossier nadien raadplegen, aanvullen met bijkomende stukken
// (parameters, kenmerken, notities, brieven) en een aangepast .docx laten
// regenereren zonder alles opnieuw aan te leveren.
//
// Privacy: de invoer is per conventie al geanonimiseerd (AGENTS.md) — dit
// bewaart dus geen persoonsgegevens, net zoals het gegenereerde bestand zelf
// (lib/word/bestandenCache.ts, zelfde 24u-TTL en dezelfde Supabase-met-
// in-memory-fallback-aanpak: op serverless zou een kale Map sessies al na
// seconden "kwijt" zijn). Afbeeldingen (afbeeldingenJson) worden bewust NIET
// mee bewaard — te groot; een regeneratie kan ze opnieuw aanleveren.
//
// Vereiste tabel (SQL, eenmalig in de Supabase SQL Editor — zie ook
// supabase/schema.sql):
//
//   create table werkdossier_sessies (
//     token        text primary key,
//     soort        text not null,
//     invoer       jsonb not null,
//     bestandsnaam text not null,
//     download_url text not null,
//     historiek    jsonb not null,
//     aangemaakt   timestamptz not null,
//     bijgewerkt   timestamptz not null,
//     verloopt_om  timestamptz not null
//   );

import { maakServiceClient } from "@/lib/supabase/server";

// Zelfde 24 uur als de downloadUrl van het gegenereerde bestand.
const TTL_MS = 24 * 60 * 60 * 1000;
const TABEL = "werkdossier_sessies";

/** Welke generator deze sessie voedde — bepaalt hoe geregenereerd wordt. */
export type SessieSoort = "werkdossier" | "modeldocument";

export interface SessieHistoriekItem {
  tijdstip: string;
  samenvatting: string;
  downloadUrl: string;
  bestandsnaam: string;
}

export interface WerkdossierSessie {
  token: string;
  soort: SessieSoort;
  /**
   * De volledige generatie-invoer (geanonimiseerd per conventie):
   * - soort "werkdossier": de JSON-body van genereerWerkdossierAlsWord;
   * - soort "modeldocument": { modeldocumentId, query } met de queryparameters
   *   van haalModeldocumentAlsWord.
   */
  invoer: Record<string, unknown>;
  bestandsnaam: string;
  downloadUrl: string;
  /** Elke (re)generatie, chronologisch — de laatste is de actuele. */
  historiek: SessieHistoriekItem[];
  aangemaakt: string;
  bijgewerkt: string;
  verlooptOm: string;
}

/** Samenvatting voor lijstweergaven (zonder de volledige invoer). */
export interface SessieSamenvatting {
  token: string;
  soort: SessieSoort;
  modeldocumentId?: string;
  bestandsnaam: string;
  downloadUrl: string;
  aantalGeneraties: number;
  aangemaakt: string;
  bijgewerkt: string;
  verlooptOm: string;
}

const geheugen = new Map<string, WerkdossierSessie>();

function ruimGeheugenOp() {
  const nu = Date.now();
  for (const [token, sessie] of geheugen) {
    if (new Date(sessie.verlooptOm).getTime() < nu) geheugen.delete(token);
  }
}

function naarRij(sessie: WerkdossierSessie) {
  return {
    token: sessie.token,
    soort: sessie.soort,
    invoer: sessie.invoer,
    bestandsnaam: sessie.bestandsnaam,
    download_url: sessie.downloadUrl,
    historiek: sessie.historiek,
    aangemaakt: sessie.aangemaakt,
    bijgewerkt: sessie.bijgewerkt,
    verloopt_om: sessie.verlooptOm,
  };
}

interface SessieRij {
  token: string;
  soort: SessieSoort;
  invoer: Record<string, unknown>;
  bestandsnaam: string;
  download_url: string;
  historiek: SessieHistoriekItem[];
  aangemaakt: string;
  bijgewerkt: string;
  verloopt_om: string;
}

function uitRij(rij: SessieRij): WerkdossierSessie {
  return {
    token: rij.token,
    soort: rij.soort,
    invoer: rij.invoer,
    bestandsnaam: rij.bestandsnaam,
    downloadUrl: rij.download_url,
    historiek: rij.historiek,
    aangemaakt: rij.aangemaakt,
    bijgewerkt: rij.bijgewerkt,
    verlooptOm: rij.verloopt_om,
  };
}

export function modeldocumentIdVanSessie(sessie: Pick<WerkdossierSessie, "soort" | "invoer">): string | undefined {
  return typeof sessie.invoer.modeldocumentId === "string" ? sessie.invoer.modeldocumentId : undefined;
}

export function naarSamenvatting(sessie: WerkdossierSessie): SessieSamenvatting {
  return {
    token: sessie.token,
    soort: sessie.soort,
    modeldocumentId: modeldocumentIdVanSessie(sessie),
    bestandsnaam: sessie.bestandsnaam,
    downloadUrl: sessie.downloadUrl,
    aantalGeneraties: sessie.historiek.length,
    aangemaakt: sessie.aangemaakt,
    bijgewerkt: sessie.bijgewerkt,
    verlooptOm: sessie.verlooptOm,
  };
}

/** Maakt een nieuwe sessie aan na een geslaagde generatie. */
export async function maakSessie(
  soort: SessieSoort,
  invoer: Record<string, unknown>,
  levering: { bestandsnaam: string; downloadUrl: string }
): Promise<WerkdossierSessie> {
  const nu = new Date();
  const sessie: WerkdossierSessie = {
    token: crypto.randomUUID(),
    soort,
    invoer,
    bestandsnaam: levering.bestandsnaam,
    downloadUrl: levering.downloadUrl,
    historiek: [
      { tijdstip: nu.toISOString(), samenvatting: "Eerste generatie", downloadUrl: levering.downloadUrl, bestandsnaam: levering.bestandsnaam },
    ],
    aangemaakt: nu.toISOString(),
    bijgewerkt: nu.toISOString(),
    verlooptOm: new Date(nu.getTime() + TTL_MS).toISOString(),
  };

  const sb = maakServiceClient();
  if (sb) {
    // Opportunistische opruiming, zelfde patroon als bestandenCache.
    await sb.from(TABEL).delete().lt("verloopt_om", nu.toISOString());
    const { error } = await sb.from(TABEL).insert(naarRij(sessie));
    if (!error) return sessie;
    // Opslagfout (bv. tabel ontbreekt): in-memory fallback, generatie faalt nooit.
  }
  ruimGeheugenOp();
  geheugen.set(sessie.token, sessie);
  return sessie;
}

export async function haalSessie(token: string): Promise<WerkdossierSessie | undefined> {
  const sb = maakServiceClient();
  if (sb) {
    const { data } = await sb.from(TABEL).select("*").eq("token", token).maybeSingle();
    if (data) {
      const sessie = uitRij(data as SessieRij);
      if (new Date(sessie.verlooptOm).getTime() < Date.now()) {
        await sb.from(TABEL).delete().eq("token", token);
        return undefined;
      }
      return sessie;
    }
  }
  const sessie = geheugen.get(token);
  if (!sessie) return undefined;
  if (new Date(sessie.verlooptOm).getTime() < Date.now()) {
    geheugen.delete(token);
    return undefined;
  }
  return sessie;
}

/** Alle niet-verlopen sessies, recentst bijgewerkt eerst. */
export async function lijstSessies(): Promise<SessieSamenvatting[]> {
  const sb = maakServiceClient();
  if (sb) {
    const { data } = await sb
      .from(TABEL)
      .select("*")
      .gt("verloopt_om", new Date().toISOString())
      .order("bijgewerkt", { ascending: false });
    if (data) return (data as SessieRij[]).map((r) => naarSamenvatting(uitRij(r)));
  }
  ruimGeheugenOp();
  return [...geheugen.values()]
    .sort((a, b) => b.bijgewerkt.localeCompare(a.bijgewerkt))
    .map(naarSamenvatting);
}

/**
 * Bewaart een bijgewerkte sessie na een regeneratie: nieuwe invoer, nieuwe
 * levering, historiekregel erbij. De TTL schuift mee op (opnieuw 24 uur vanaf
 * de laatste wijziging — wie actief aan een dossier werkt, verliest het niet).
 */
export async function werkSessieBij(
  sessie: WerkdossierSessie,
  nieuweInvoer: Record<string, unknown>,
  levering: { bestandsnaam: string; downloadUrl: string },
  samenvatting: string
): Promise<WerkdossierSessie> {
  const nu = new Date();
  const bijgewerkt: WerkdossierSessie = {
    ...sessie,
    invoer: nieuweInvoer,
    bestandsnaam: levering.bestandsnaam,
    downloadUrl: levering.downloadUrl,
    historiek: [
      ...sessie.historiek,
      { tijdstip: nu.toISOString(), samenvatting, downloadUrl: levering.downloadUrl, bestandsnaam: levering.bestandsnaam },
    ],
    bijgewerkt: nu.toISOString(),
    verlooptOm: new Date(nu.getTime() + TTL_MS).toISOString(),
  };
  const sb = maakServiceClient();
  if (sb) {
    const { error } = await sb.from(TABEL).update(naarRij(bijgewerkt)).eq("token", sessie.token);
    if (!error) return bijgewerkt;
  }
  geheugen.set(sessie.token, bijgewerkt);
  return bijgewerkt;
}
