import { test, expect } from "@playwright/test";
import { ROUTES } from "./routes.manifest";

/**
 * KRITISCHE Auth-Gating-Suite (Definition of Done #1, oberstes Prinzip).
 *
 * Erzeugt GENAU EINEN Testfall pro Manifest-Eintrag (ROUTES.length):
 *  - Seiten -> Redirect auf /login (mit callbackUrl), kein Daten-Leak.
 *  - API    -> 401 ohne Fachdaten im Body.
 *
 * NICHT in der Sandbox ausführbar (kein Server/DB) — deferred. Wird über
 * `npm run test:e2e:gating` gegen einen laufenden Server ausgeführt.
 *
 * Negativ-Probe (CI): Entfernen eines Layout-Guards oder einer Manifest-Route
 * muss diese Suite rot machen.
 */

// Erzwingt anonymen Zustand: keine gespeicherte Session.
test.use({ storageState: { cookies: [], origins: [] } });

// Fachbegriffe, die in einem 401/Redirect-Body NIE auftauchen dürfen.
const LEAK_TERMS = [
  "funkrufname",
  "wehrfuehrer",
  "einsatzbereit",
  "passwort",
  "kennzeichen",
];

function assertNoLeak(body: string) {
  const lower = body.toLowerCase();
  for (const term of LEAK_TERMS) {
    expect(lower, `Daten-Leak: Body enthält "${term}"`).not.toContain(term);
  }
}

for (const route of ROUTES) {
  if (route.expectWhenAnon === "redirect") {
    test(`Seite ${route.path}: anonym -> Redirect auf /login`, async ({
      page,
    }) => {
      const response = await page.goto(route.path);
      await expect(page).toHaveURL(/\/login/);
      // callbackUrl bewahrt das ursprüngliche Ziel.
      expect(page.url()).toContain("callbackUrl");
      const body = await page.content();
      assertNoLeak(body);
      // Kein 500 o. ä.
      if (response) expect(response.status()).toBeLessThan(500);
    });
  } else {
    test(`API ${route.path}: anonym -> 401 ohne Daten-Leak`, async ({
      request,
    }) => {
      // /api/geo/geocode ist POST-only; health ist GET. Beide gehen durch apiAuth().
      const res = route.path.includes("geocode")
        ? await request.post(route.path, { data: { address: "x" } })
        : await request.get(route.path);
      expect(res.status()).toBe(401);
      assertNoLeak(await res.text());
    });
  }
}

test.describe("Öffentliche Routen bleiben anonym erreichbar", () => {
  test("Login-Seite ist anonym 200", async ({ page }) => {
    const res = await page.goto("/login");
    expect(res?.status()).toBeLessThan(400);
    await expect(page.getByRole("heading", { name: "Anmelden" })).toBeVisible();
  });

  test("Container-Health ist anonym 200", async ({ request }) => {
    const res = await request.get("/api/health");
    expect(res.status()).toBe(200);
    expect(await res.json()).toEqual({ status: "ok" });
  });
});
