/**
 * CORS policy verification harness.
 *
 * Exercises the pure helpers in src/lib/http/cors.ts with simulated requests
 * (real NextRequest/NextResponse instances) and asserts the policy:
 *   - preflight from an allowed origin  -> 204 + correct headers
 *   - preflight from a disallowed origin -> 403
 *   - normal request, disallowed origin -> 403
 *   - no Origin header / allowed origin -> undefined (continue)
 *   - allowlist normalization (trailing slash, case, default port)
 *   - never emits `Access-Control-Allow-Origin: *`
 *
 * Run: node scripts/verify_cors.mjs
 * (Node >= 23.6 / 24 runs the imported .ts directly via built-in type stripping;
 *  no tsx required.)
 */
import assert from "node:assert/strict";
import { NextRequest } from "next/server";
import {
  getAllowedOrigins,
  isOriginAllowed,
  corsHeadersFor,
  handleCors,
  originComparisonKey,
  CORS_ALLOWED_METHODS,
  CORS_ERROR_CODE,
} from "../src/lib/http/cors.ts";

let passed = 0;
let failed = 0;

function check(name, fn) {
  try {
    fn();
    passed += 1;
    console.log(`  ok  ${name}`);
  } catch (err) {
    failed += 1;
    console.error(`FAIL  ${name}`);
    console.error(String(err instanceof Error ? err.stack : err).replace(/^/gm, "      "));
  }
}

/** Env that looks like production: app origin + a few extra allowlisted origins. */
const PROD_ENV = {
  CORS_ORIGINS: "https://admin.example.com, http://localhost:8080/",
  NEXT_PUBLIC_APP_URL: "https://app.example.com",
};

const APP_ORIGIN = "https://app.example.com";

function req(method, headers, url = "https://app.example.com/api/receipts") {
  return new NextRequest(url, { method, headers });
}

// ---------------------------------------------------------------------------
console.log("CORS policy verification\n");
console.log("1) Allowlist construction & normalization");

check("getAllowedOrigins returns full origins (echo form), scheme & case preserved", () => {
  const list = getAllowedOrigins(PROD_ENV);
  assert.ok(list.includes("https://app.example.com"), `NEXT_PUBLIC_APP_URL missing: ${list}`);
  assert.ok(list.includes("https://admin.example.com"), `missing admin origin: ${list}`);
  assert.ok(list.includes("http://localhost:8080"), `missing localhost origin: ${list}`);
  // Trailing slashes are stripped during normalization (spec).
  assert.ok(!list.some((o) => o.endsWith("/")), `trailing slash survived: ${list}`);
});

check("allowlist is de-duplicated by comparison key; app origin wins over duplicates", () => {
  const dupEnv = {
    CORS_ORIGINS: "https://app.example.com, https://APP.EXAMPLE.COM:443",
    NEXT_PUBLIC_APP_URL: "https://app.example.com",
  };
  // All three spellings share the key "app.example.com" -> exactly one entry,
  // and it is the canonical NEXT_PUBLIC_APP_URL spelling (added first).
  const list = getAllowedOrigins(dupEnv);
  assert.deepEqual(list, ["https://app.example.com"], `expected single canonical entry: ${list}`);
  const keys = getAllowedOrigins(PROD_ENV).map(originComparisonKey);
  assert.equal(new Set(keys).size, keys.length, `duplicate keys: ${keys}`);
});

check("comparison key strips scheme, trailing slash, lowercases host, collapses default port", () => {
  assert.equal(originComparisonKey("https://App.Example.com/"), "app.example.com");
  assert.equal(originComparisonKey("https://app.example.com:443"), "app.example.com");
  assert.equal(originComparisonKey("http://app.example.com:80"), "app.example.com");
  assert.equal(originComparisonKey("HTTPS://app.example.com:3000/"), "app.example.com:3000");
  assert.equal(originComparisonKey("http://localhost:8080"), "localhost:8080");
});

check("comparison key drops path/query/fragment defensively", () => {
  assert.equal(
    originComparisonKey("https://app.example.com/some/path?x=1#frag"),
    "app.example.com"
  );
});

check("comparison key handles IPv6 literals", () => {
  assert.equal(originComparisonKey("http://[::1]:3000"), "[::1]:3000");
  assert.equal(originComparisonKey("http://[::1]"), "[::1]");
});

// ---------------------------------------------------------------------------
console.log("\n2) isOriginAllowed");

check("no Origin header (null/empty) is allowed (curl, same-origin, server-to-server)", () => {
  assert.equal(isOriginAllowed(null, PROD_ENV), true);
  assert.equal(isOriginAllowed("", PROD_ENV), true);
});

check("exact allowed origin matches", () => {
  assert.equal(isOriginAllowed(APP_ORIGIN, PROD_ENV), true);
  assert.equal(isOriginAllowed("https://admin.example.com", PROD_ENV), true);
  assert.equal(isOriginAllowed("http://localhost:8080", PROD_ENV), true);
});

check("normalization: trailing slash, mixed case, explicit default port all match", () => {
  assert.equal(isOriginAllowed("https://app.example.com/", PROD_ENV), true);
  assert.equal(isOriginAllowed("HTTPS://APP.EXAMPLE.COM", PROD_ENV), true);
  assert.equal(isOriginAllowed("https://app.example.com:443", PROD_ENV), true);
});

check("disallowed origins are rejected (never *, exact match only)", () => {
  assert.equal(isOriginAllowed("https://evil.example.com", PROD_ENV), false);
  assert.equal(isOriginAllowed("https://example.com", PROD_ENV), false);
  assert.equal(isOriginAllowed("http://localhost:9999", PROD_ENV), false);
  assert.equal(isOriginAllowed("null", PROD_ENV), false);
});

check("substring / suffix attacks do not match", () => {
  assert.equal(isOriginAllowed("https://app.example.com.evil.com", PROD_ENV), false);
  assert.equal(isOriginAllowed("https://app.example.com.evil.com:443", PROD_ENV), false);
  assert.equal(isOriginAllowed("https://evilexample.com", PROD_ENV), false);
  assert.equal(isOriginAllowed("https://admin.example.com.evil.com", PROD_ENV), false);
});

check("host + port are exact; scheme is ignored for comparison (documented policy)", () => {
  // Port is part of the exact match.
  assert.equal(isOriginAllowed("https://app.example.com:444", PROD_ENV), false);
  assert.equal(isOriginAllowed("http://localhost:8081", PROD_ENV), false);
  // The http/https prefix is stripped for comparison (policy), so the same
  // host:port under the other scheme is treated as the same origin.
  assert.equal(isOriginAllowed("http://app.example.com", PROD_ENV), true);
});

check("empty allowlist => same-origin only (everything with an Origin rejected)", () => {
  const empty = { CORS_ORIGINS: "", NEXT_PUBLIC_APP_URL: "" };
  assert.equal(isOriginAllowed(null, empty), true);
  assert.equal(isOriginAllowed("https://app.example.com", empty), false);
});

// ---------------------------------------------------------------------------
console.log("\n3) corsHeadersFor");

check("allowed origin -> exact echo + Vary: Origin + credentials; never '*'", () => {
  const h = corsHeadersFor(APP_ORIGIN, PROD_ENV);
  assert.equal(h["Access-Control-Allow-Origin"], APP_ORIGIN);
  assert.equal(h["Vary"], "Origin");
  assert.equal(h["Access-Control-Allow-Credentials"], "true");
  assert.ok(!Object.values(h).includes("*"), "wildcard leaked into headers");
});

check("disallowed / missing origin -> no CORS headers", () => {
  assert.deepEqual(corsHeadersFor("https://evil.example.com", PROD_ENV), {});
  assert.deepEqual(corsHeadersFor(null, PROD_ENV), {});
  assert.deepEqual(corsHeadersFor("", PROD_ENV), {});
});

// ---------------------------------------------------------------------------
console.log("\n4) handleCors — preflight");

check("preflight from allowed origin -> 204 with full header set", () => {
  const res = handleCors(
    req("OPTIONS", {
      origin: APP_ORIGIN,
      "access-control-request-method": "POST",
      "access-control-request-headers": "content-type, authorization",
    }),
    PROD_ENV
  );
  assert.ok(res, "expected a response");
  assert.equal(res.status, 204);
  assert.equal(res.headers.get("access-control-allow-origin"), APP_ORIGIN);
  assert.equal(res.headers.get("vary"), "Origin");
  assert.equal(res.headers.get("access-control-allow-credentials"), "true");
  assert.equal(res.headers.get("access-control-allow-methods"), CORS_ALLOWED_METHODS);
  assert.equal(res.headers.get("access-control-max-age"), "600");
  assert.equal(res.headers.get("access-control-allow-headers"), "content-type, authorization");
});

check("preflight echo uses the exact request origin, never a wildcard", () => {
  const res = handleCors(
    req("OPTIONS", {
      origin: "https://admin.example.com",
      "access-control-request-method": "GET",
    }),
    PROD_ENV
  );
  assert.ok(res);
  assert.equal(res.status, 204);
  const acao = res.headers.get("access-control-allow-origin");
  assert.equal(acao, "https://admin.example.com");
  assert.ok(acao && !acao.includes("*"), "Access-Control-Allow-Origin contains '*'");
});

check("preflight from disallowed origin -> 403, no ACAO header", () => {
  const res = handleCors(
    req("OPTIONS", {
      origin: "https://evil.example.com",
      "access-control-request-method": "POST",
    }),
    PROD_ENV
  );
  assert.ok(res);
  assert.equal(res.status, 403);
  assert.equal(res.headers.get("access-control-allow-origin"), null, "no ACAO on refusal");
});

check("preflight 403 carries the machine-readable error code", async () => {
  const res = handleCors(
    req("OPTIONS", {
      origin: "https://evil.example.com",
      "access-control-request-method": "POST",
    }),
    PROD_ENV
  );
  assert.ok(res);
  const body = await res.json();
  assert.deepEqual(body, { error: CORS_ERROR_CODE });
});

check("Access-Control-Allow-Headers echo is validated (invalid tokens dropped)", () => {
  const res = handleCors(
    req("OPTIONS", {
      origin: APP_ORIGIN,
      "access-control-request-method": "PUT",
      "access-control-request-headers": "content-type, bad header!, x-foo",
    }),
    PROD_ENV
  );
  assert.ok(res);
  assert.equal(res.headers.get("access-control-allow-headers"), "content-type, x-foo");
});

check("Access-Control-Allow-Headers echo is bounded (oversized input omitted)", () => {
  const res = handleCors(
    req("OPTIONS", {
      origin: APP_ORIGIN,
      "access-control-request-method": "PUT",
      "access-control-request-headers": "x-big-" + "a".repeat(5000),
    }),
    PROD_ENV
  );
  assert.ok(res);
  assert.equal(res.headers.get("access-control-allow-headers"), null);
});

check("Access-Control-Allow-Headers echo is de-duplicated", () => {
  const res = handleCors(
    req("OPTIONS", {
      origin: APP_ORIGIN,
      "access-control-request-method": "POST",
      "access-control-request-headers": "content-type, content-type, authorization",
    }),
    PROD_ENV
  );
  assert.ok(res);
  assert.equal(res.headers.get("access-control-allow-headers"), "content-type, authorization");
});

// ---------------------------------------------------------------------------
console.log("\n5) handleCors — non-preflight");

check("normal request from allowed origin -> undefined (continue)", () => {
  const res = handleCors(req("GET", { origin: APP_ORIGIN }), PROD_ENV);
  assert.equal(res, undefined);
});

check("normal request with no Origin -> undefined (continue)", () => {
  const res = handleCors(req("GET", {}), PROD_ENV);
  assert.equal(res, undefined);
});

check("normal request from disallowed origin -> 403", () => {
  const res = handleCors(req("GET", { origin: "https://evil.example.com" }), PROD_ENV);
  assert.ok(res);
  assert.equal(res.status, 403);
});

check("bare OPTIONS without Access-Control-Request-Method is not a preflight", () => {
  // Disallowed origin on a bare OPTIONS is still refused (cross-origin).
  const disallowed = handleCors(req("OPTIONS", { origin: "https://evil.example.com" }), PROD_ENV);
  assert.ok(disallowed);
  assert.equal(disallowed.status, 403);
  // Allowed origin on a bare OPTIONS passes through.
  const allowed = handleCors(req("OPTIONS", { origin: APP_ORIGIN }), PROD_ENV);
  assert.equal(allowed, undefined);
});

check("POST (credentials path) from allowed origin -> undefined", () => {
  const res = handleCors(req("POST", { origin: APP_ORIGIN }), PROD_ENV);
  assert.equal(res, undefined);
});

// ---------------------------------------------------------------------------
console.log("\n6) global: no '*' is ever emitted as a header value");

function collectHeaderValues() {
  const values = [];
  const origins = ["https://app.example.com", "https://admin.example.com", "http://localhost:8080"];
  for (const origin of origins) {
    const preflight = handleCors(
      req("OPTIONS", {
        origin,
        "access-control-request-method": "GET",
        "access-control-request-headers": "content-type, authorization",
      }),
      PROD_ENV
    );
    if (preflight) preflight.headers.forEach((v) => values.push(v));
    values.push(...Object.values(corsHeadersFor(origin, PROD_ENV)));
  }
  return values;
}

check("no emitted header value equals or contains '*'", () => {
  const values = collectHeaderValues();
  assert.ok(values.length > 0, "expected to collect some header values");
  for (const v of values) {
    assert.ok(!v.includes("*"), `wildcard value emitted: ${JSON.stringify(v)}`);
  }
});

check("allowlist itself contains no wildcard entries", () => {
  for (const origin of getAllowedOrigins(PROD_ENV)) {
    assert.ok(!origin.includes("*"), `wildcard in allowlist: ${origin}`);
  }
});

// ---------------------------------------------------------------------------
console.log(`\n${passed} passed, ${failed} failed`);
if (failed > 0) {
  console.error("CORS verification FAILED");
  process.exit(1);
}
console.log("CORS verification PASSED");
