/* =====================================================================
   middleware/gate.js — Zugangs-Schranke vor der ganzen Website. 1:1 portiert aus
   functions/_middleware.js (onRequest), auf Express-Middleware-Stil umgestellt (next() statt
   context.next(), req/res statt Request/Response). Gleiche Regeln, gleiche Reihenfolge:

   - /admin/* nie anfassen (eigener, separater Worker mit GitHub-OAuth).
   - /gate-logout immer erreichbar.
   - Rechtstexte (Impressum, Datenschutz, AGB, Widerruf) immer ohne Code erreichbar.
   - Fail-open, falls die Zugangs-Secrets fehlen (lieber offen als sich selbst aussperren).
   - /verwaltung/* + /api/verwaltung/* bleiben IMMER geschützt, auch wenn SITE_PUBLIC=true.
   - SITE_PUBLIC=true schaltet den Rest der Seite öffentlich (außer /verwaltung).
   - API-Routen bekommen bei fehlender Sitzung 401-JSON statt HTML-Redirect.
   ===================================================================== */

import { COOKIE_NAME, ROLE_COOKIE_NAME, SESSION_TAGE, signSession, verifySession } from "../lib/auth.js";
import {
  VERWALTUNG_COOKIE_NAME,
  VERWALTUNG_SESSION_STUNDEN,
  signVerwaltungSession,
  verifyVerwaltungSession,
} from "../lib/verwaltung-auth.js";

const OEFFENTLICHE_SEITEN = new Set(["/impressum", "/datenschutz", "/agb", "/widerruf", "/muster-widerrufsformular"]);

function istOeffentlichErreichbar(pfad) {
  const ohneSlash = pfad.endsWith("/") && pfad.length > 1 ? pfad.slice(0, -1) : pfad;
  if (OEFFENTLICHE_SEITEN.has(ohneSlash)) return true;
  if (pfad.startsWith("/_astro/") && pfad.endsWith(".css")) return true;
  if (pfad === "/img/gate-avatar-dogi.webp" || pfad === "/img/gate-avatar-vanvan.webp") return true;
  if (/^\/(logo\.png|favicon\.ico|favicon-\d+x\d+\.png|apple-touch-icon\.png|icon-\d+(-maskable)?\.png|sw\.js|manifest\.webmanifest)$/.test(pfad)) return true;
  return false;
}

export async function gateAuthHandler(req, res) {
  const code = (req.body?.code || "").trim();
  const next = typeof req.body?.next === "string" && req.body.next.startsWith("/") ? req.body.next : "/";

  let role = null;
  if (process.env.SITE_ACCESS_CODE_QCIGA && code === process.env.SITE_ACCESS_CODE_QCIGA) role = "qciga";
  else if (process.env.SITE_ACCESS_CODE_VANVAN && code === process.env.SITE_ACCESS_CODE_VANVAN) role = "vanvan";

  if (!role) {
    return res.status(401).json({ ok: false, error: "Falscher Zugangscode." });
  }

  const session = await signSession(role, process.env.SITE_ACCESS_SECRET);
  const maxAge = SESSION_TAGE * 24 * 60 * 60 * 1000;
  res.cookie(COOKIE_NAME, session, { path: "/", maxAge, httpOnly: true, secure: true, sameSite: "lax" });
  res.cookie(ROLE_COOKIE_NAME, role, { path: "/", maxAge, secure: true, sameSite: "lax" });
  return res.json({ ok: true, next });
}

export async function verwaltungAuthHandler(req, res) {
  const code = (req.body?.code || "").trim();
  const next = typeof req.body?.next === "string" && req.body.next.startsWith("/") ? req.body.next : "/verwaltung/";

  const codeGueltig =
    (process.env.SITE_ACCESS_CODE_QCIGA && code === process.env.SITE_ACCESS_CODE_QCIGA) ||
    (process.env.SITE_ACCESS_CODE_VANVAN && code === process.env.SITE_ACCESS_CODE_VANVAN);
  if (!codeGueltig) {
    return res.status(401).json({ ok: false, error: "Falscher Code." });
  }

  const session = await signVerwaltungSession(process.env.VERWALTUNG_SESSION_SECRET);
  const maxAge = VERWALTUNG_SESSION_STUNDEN * 60 * 60 * 1000;
  res.cookie(VERWALTUNG_COOKIE_NAME, session, { path: "/", maxAge, httpOnly: true, secure: true, sameSite: "lax" });
  return res.json({ ok: true, next });
}

export function logoutHandler(req, res) {
  res.clearCookie(COOKIE_NAME, { path: "/" });
  res.clearCookie(ROLE_COOKIE_NAME, { path: "/" });
  res.clearCookie(VERWALTUNG_COOKIE_NAME, { path: "/" });
  return res.json({ ok: true });
}

/** Die eigentliche Middleware, vor JEDER Anfrage montiert (siehe index.js). */
export function gateMiddleware(req, res, next) {
  const pfad = req.path;

  if (pfad.startsWith("/admin")) return next();
  if (pfad === "/gate-logout" && req.method === "POST") return logoutHandler(req, res);
  if (istOeffentlichErreichbar(pfad)) return next();

  const codesKonfiguriert = !!(process.env.SITE_ACCESS_SECRET && (process.env.SITE_ACCESS_CODE_QCIGA || process.env.SITE_ACCESS_CODE_VANVAN));
  if (!codesKonfiguriert) return next();

  const immerGeschuetzterPfad = pfad.startsWith("/verwaltung") || pfad.startsWith("/api/verwaltung");

  const sitePublic = process.env.SITE_PUBLIC === "true";
  if (sitePublic && !immerGeschuetzterPfad) return next();

  if (pfad === "/gate-auth" && req.method === "POST") return gateAuthHandler(req, res);

  const sessionToken = req.cookies?.[COOKIE_NAME];

  (async () => {
    const payload = sessionToken ? await verifySession(sessionToken, process.env.SITE_ACCESS_SECRET) : null;

    if (payload) {
      if (!immerGeschuetzterPfad) return next();

      if (pfad === "/verwaltung-code.html" || pfad === "/verwaltung-code") return next();
      if (pfad === "/verwaltung-auth" && req.method === "POST") return verwaltungAuthHandler(req, res);

      if (!process.env.VERWALTUNG_SESSION_SECRET) return next();

      const vwToken = req.cookies?.[VERWALTUNG_COOKIE_NAME];
      const vwPayload = vwToken ? await verifyVerwaltungSession(vwToken, process.env.VERWALTUNG_SESSION_SECRET) : null;
      if (vwPayload) return next();

      if (pfad.startsWith("/api/")) {
        return res.status(401).json({ ok: false, error: "Zusätzlicher Verwaltungs-Code erforderlich." });
      }
      const vwNext = pfad + (req.originalUrl.includes("?") ? "?" + req.originalUrl.split("?")[1] : "");
      return res.redirect(302, `/verwaltung-code.html?next=${encodeURIComponent(vwNext)}`);
    }

    if (pfad === "/gate.html" || pfad === "/gate") return next();

    if (pfad.startsWith("/api/")) {
      return res.status(401).json({ ok: false, error: "Nicht angemeldet." });
    }

    const nextParam = pfad + (req.originalUrl.includes("?") ? "?" + req.originalUrl.split("?")[1] : "");
    return res.redirect(302, `/gate?next=${encodeURIComponent(nextParam)}`);
  })();
}
