'use strict';

// Security invariant: every API router mount is either explicitly public or carries
// requireAuth (+ CSRF for authenticated routers). This is a static guard so a new
// route added without auth/CSRF fails CI instead of silently exposing data.
const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');

const server = fs.readFileSync(path.join(__dirname, '..', 'server.cts'), 'utf8');

// Routers that are intentionally public (or handle their own auth internally).
const PUBLIC_ROUTERS = new Set([
  'auth', // login/register/csrf-token are public; authed sub-routes guard themselves
  'authOidc', // OIDC login/callback are public entry points
  'calendarFeed', // token-authenticated ICS feed (no session)
  'about', // public marketing/info
  'privacy', // public policy
  'version', // public version / release-notes / update-status
]);

// Match: app.use('<path>', <middleware...>, require('./routes/<file>.cts'))
const mountRe =
  /app\.use\(\s*['"](\/api\/[^'"]+)['"]([\s\S]*?)require\(\s*['"]\.\/routes\/([A-Za-z0-9_-]+)\.cts['"]\s*\)/g;

const mounts = [];
for (let m; (m = mountRe.exec(server));) {
  mounts.push({ path: m[1], middleware: m[2], router: m[3] });
}

test('server.cts mounts are discoverable', () => {
  assert.ok(mounts.length >= 20, `expected many router mounts, found ${mounts.length}`);
});

test('every non-public router mount requires authentication', () => {
  const offenders = mounts
    .filter((m) => !PUBLIC_ROUTERS.has(m.router))
    .filter((m) => !/requireAuth/.test(m.middleware))
    .map((m) => `${m.path} → routes/${m.router}.cts`);
  assert.deepEqual(
    offenders,
    [],
    `router mounts missing requireAuth:\n  ${offenders.join('\n  ')}`,
  );
});

test('every authenticated router mount enforces CSRF', () => {
  const offenders = mounts
    .filter((m) => !PUBLIC_ROUTERS.has(m.router))
    .filter((m) => !/csrfMiddleware/.test(m.middleware))
    .map((m) => `${m.path} → routes/${m.router}.cts`);
  assert.deepEqual(
    offenders,
    [],
    `authed router mounts missing csrfMiddleware:\n  ${offenders.join('\n  ')}`,
  );
});

test('admin router mounts require admin', () => {
  const adminMounts = mounts.filter(
    (m) => m.path.startsWith('/api/admin') || m.router === 'aboutAdmin' || m.router === 'status',
  );
  assert.ok(adminMounts.length >= 1, 'expected at least one admin mount');
  const offenders = adminMounts
    .filter((m) => !/requireAdmin/.test(m.middleware))
    .map((m) => `${m.path} → routes/${m.router}.cts`);
  assert.deepEqual(
    offenders,
    [],
    `admin mounts missing requireAdmin:\n  ${offenders.join('\n  ')}`,
  );
});
