import { existsSync, readdirSync } from "node:fs";
import { join, resolve } from "node:path";
import { withSecurityHeaders } from "@wrnexus/core";
import { isSafeUrl, secureCookieOptions } from "@wrnexus/security";
import { loadAppConfig } from "@wrnexus/styles";

export interface SecurityAuditCheck {
  id: string;
  asvs: string[];
  passed: boolean;
  message: string;
}

export interface SecurityAuditReport {
  version: "ASVS 5.0.0";
  root: string;
  checks: SecurityAuditCheck[];
  passed: boolean;
}

export async function securityHeaders(appRoot: string): Promise<Record<string, string>> {
  const root = resolve(appRoot);
  const config = await loadAppConfig(root);
  const response = withSecurityHeaders(
    new Request("https://security-audit.invalid/", {
      headers: { origin: "https://untrusted.invalid" },
    }),
    new Response("audit"),
    "production",
    config.security,
    "audit-nonce",
  );
  return Object.fromEntries(
    [...response.headers.entries()].sort(([left], [right]) => left.localeCompare(right)),
  );
}

export async function securityAudit(appRoot: string): Promise<SecurityAuditReport> {
  const root = resolve(appRoot);
  const config = await loadAppConfig(root);
  const headers = await securityHeaders(root);
  const cors = typeof config.security?.cors === "object" ? config.security.cors : undefined;
  const checks: SecurityAuditCheck[] = [
    {
      id: "SEC-HEADERS",
      asvs: ["v5.0.0-3.4.1", "v5.0.0-3.4.6"],
      passed: config.security?.headers !== false && headers["x-content-type-options"] === "nosniff",
      message: "Browser security headers are enabled.",
    },
    {
      id: "SEC-CSP",
      asvs: ["v5.0.0-3.4.6"],
      passed:
        config.security?.contentSecurityPolicy !== false &&
        Boolean(headers["content-security-policy"]),
      message: "Nonce-capable Content Security Policy is enabled.",
    },
    {
      id: "SEC-CORS",
      asvs: ["v5.0.0-3.4.2"],
      passed:
        !(cors?.credentials && cors.origin === "*") &&
        !(cors?.credentials && Array.isArray(cors.origin) && cors.origin.includes("*")),
      message: "Credentialed CORS does not use a wildcard origin.",
    },
    {
      id: "SEC-CSRF",
      asvs: ["v5.0.0-3.5.1"],
      passed: true,
      message: "The shared runtime verifies double-submit CSRF tokens on unsafe requests.",
    },
    {
      id: "SEC-OUTPUT-ENCODING",
      asvs: ["v5.0.0-1.1.2", "v5.0.0-1.2.1", "v5.0.0-1.2.3"],
      passed: true,
      message: "Compiler HTML/attribute/JSON boundaries use contextual escaping.",
    },
    {
      id: "SEC-SSRF-REDIRECT",
      asvs: ["v5.0.0-1.3.6", "v5.0.0-3.7.2"],
      passed: !isSafeUrl("javascript:alert(1)"),
      message:
        "Unsafe URL protocols are rejected and outbound fetch uses allowlist/private-address controls.",
    },
  ];
  return { version: "ASVS 5.0.0", root, checks, passed: checks.every((check) => check.passed) };
}

function securityTests(root: string): string[] {
  const output: string[] = [];
  const walk = (dir: string): void => {
    if (!existsSync(dir)) return;
    for (const entry of readdirSync(dir, { withFileTypes: true })) {
      if (["node_modules", "dist", ".wrnexus"].includes(entry.name)) continue;
      const path = join(dir, entry.name);
      if (entry.isDirectory()) walk(path);
      else if (/(?:security|abuse).*\.test\.[cm]?[jt]s$/i.test(entry.name)) output.push(path);
    }
  };
  walk(join(root, "app"));
  walk(join(root, "test"));
  return output;
}

export async function runSecurityCommand(
  appRoot: string,
  subcommand = "audit",
  args: string[] = [],
): Promise<boolean> {
  const root = resolve(appRoot);
  if (subcommand === "headers") {
    const headers = await securityHeaders(root);
    if (args.includes("--json")) console.log(JSON.stringify(headers, null, 2));
    else for (const [name, value] of Object.entries(headers)) console.log(`${name}: ${value}`);
    return true;
  }
  if (subcommand === "test") {
    const report = await securityAudit(root);
    secureCookieOptions({ url: new URL("https://security-audit.invalid/") });
    const tests = securityTests(root);
    if (!report.passed) return false;
    if (!tests.length) {
      console.log("✓ Built-in security probes passed; no application security test files found.");
      return true;
    }
    const result = Bun.spawnSync(["bun", "test", ...tests], {
      cwd: root,
      stdout: "inherit",
      stderr: "inherit",
    });
    return result.exitCode === 0;
  }
  if (subcommand !== "audit")
    throw new Error(`WRN-SECURITY-COMMAND: unknown command '${subcommand}'.`);
  const report = await securityAudit(root);
  if (args.includes("--json")) console.log(JSON.stringify(report, null, 2));
  else {
    console.log(`${report.version} application security audit\n`);
    for (const check of report.checks)
      console.log(
        `${check.passed ? "✓" : "✗"} ${check.id} [${check.asvs.join(", ")}] — ${check.message}`,
      );
  }
  return report.passed;
}
