import { globSync } from "node:fs";
import { readFileSync } from "node:fs";
import { dirname, relative, resolve } from "node:path";
import { fileURLToPath } from "node:url";

/**
 * Statischer Default-Deny-Scanner für Server Actions (Querschnittsstandard 3).
 *
 * Reine Funktionen, damit der Beweis sowohl im Vitest-Unit-Test (offline, ohne
 * Server/DB) als auch in der Playwright-Suite (`server-actions-guard.spec.ts`)
 * wiederverwendet werden kann.
 */

const REPO_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");

/** Erkennt einen der fünf kanonischen Guards (guards.ts). */
export const GUARD_REGEX =
  /require(Session|Role|OwnBrigade|PlatformAdmin|WehrAdmin)\s*\(/;

/**
 * Genuin öffentliche "use server"-Funktionen (Login VOR der Authentifizierung).
 * Diese DÜRFEN keinen Session-Guard haben — sie sind der Einstieg. Schlüssel:
 * `<repo-relativer Pfad>:<Funktionsname>`.
 */
export const PUBLIC_ACTION_ALLOWLIST: ReadonlySet<string> = new Set([
  "src/app/(auth)/login/actions.ts:loginAction",
  "src/app/(auth)/login/actions.ts:authentikLoginAction",
]);

/**
 * Prüft den Quelltext EINER Datei. Gibt eine Liste von Verstößen
 * (`<file>: <funktionsname>`) zurück. Dateien ohne "use server"-Direktive
 * liefern nie Verstöße.
 */
export function findUnguardedActions(
  file: string,
  src: string,
  allowlist: ReadonlySet<string> = PUBLIC_ACTION_ALLOWLIST,
): string[] {
  if (!src.includes('"use server"')) return [];
  const offenders: string[] = [];
  const fns = src.split(/export async function /).slice(1);
  for (const body of fns) {
    const name = body.slice(0, body.indexOf("(")).trim();
    if (allowlist.has(`${file}:${name}`)) continue;
    // Erste ~600 Zeichen des Funktionskörpers müssen einen Guard enthalten.
    if (!GUARD_REGEX.test(body.slice(0, 600))) {
      offenders.push(`${file}: ${name}`);
    }
  }
  return offenders;
}

/**
 * Scannt das echte Repository (src/**) nach ungeschützten Server Actions.
 */
export function findUnguardedActionsInRepo(): string[] {
  const files = globSync("src/**/*.{ts,tsx}", { cwd: REPO_ROOT });
  const offenders: string[] = [];
  for (const rel of files) {
    const abs = resolve(REPO_ROOT, rel);
    const src = readFileSync(abs, "utf8");
    if (!src.includes('"use server"')) continue;
    const repoRel = relative(REPO_ROOT, abs);
    offenders.push(...findUnguardedActions(repoRel, src));
  }
  return offenders;
}
