import console from "node:console";
import { existsSync, readFileSync, readdirSync } from "node:fs";
import { dirname, join, resolve } from "node:path";
import process from "node:process";
import { fileURLToPath } from "node:url";
import { spawnSync } from "node:child_process";

const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
let passed = 0;
let failed = 0;
const failures = [];
function check(name, condition, detail = "") {
  if (condition) {
    passed++;
    console.log(`  ok   ${name}`);
    return;
  }
  failed++;
  failures.push(detail ? `${name}: ${detail}` : name);
  console.error(`  FAIL ${name}${detail ? ` — ${detail}` : ""}`);
}
function text(path) {
  return readFileSync(join(root, path), "utf8");
}
function has(path, value) {
  const source = text(path);
  return typeof value === "string" ? source.includes(value) : value.test(source);
}

const rootManifest = JSON.parse(text("package.json"));
const releaseVersion = rootManifest.version;
check(
  "repository governance documents exist",
  ["LICENSE", "SECURITY.md", "CONTRIBUTING.md", "CHANGELOG.md", "CODE_OF_CONDUCT.md"].every(
    (file) => existsSync(join(root, file)),
  ),
);
const packageManifests = readdirSync(join(root, "packages"), { withFileTypes: true })
  .filter(
    (entry) =>
      entry.isDirectory() && existsSync(join(root, "packages", entry.name, "package.json")),
  )
  .map((entry) => JSON.parse(text(`packages/${entry.name}/package.json`)));
const workspaceManifests = ["packages", "examples", "services"].flatMap((directory) =>
  readdirSync(join(root, directory), { withFileTypes: true })
    .filter(
      (entry) =>
        entry.isDirectory() && existsSync(join(root, directory, entry.name, "package.json")),
    )
    .map((entry) => JSON.parse(text(`${directory}/${entry.name}/package.json`))),
);
check(
  "package manifests avoid floating latest dependency ranges",
  ![rootManifest, ...workspaceManifests].some((manifest) =>
    [manifest.dependencies, manifest.devDependencies, manifest.peerDependencies].some((group) =>
      Object.values(group ?? {}).includes("latest"),
    ),
  ),
);
check("root version is a 0.8 release", /^0\.8\.\d+$/.test(releaseVersion));
check(
  "all framework packages use valid independent 0.8 versions",
  packageManifests.every((manifest) => /^0\.8\.\d+$/.test(manifest.version)),
);
const bunLockPackages = [
  ...text("bun.lock").matchAll(/^ {4}"packages\/[^"\r\n]+": \{\r?\n([\s\S]*?)^ {4}\},?$/gm),
].map((match) => ({
  name: /^ {6}"name": "([^"]+)"/m.exec(match[1])?.[1],
  version: /^ {6}"version": "([^"]+)"/m.exec(match[1])?.[1],
}));
const packageVersions = new Map(
  packageManifests.map((manifest) => [manifest.name, manifest.version]),
);
check(
  "bun.lock matches each independent framework package version",
  bunLockPackages.length === packageManifests.length &&
    bunLockPackages.every(({ name, version }) => packageVersions.get(name) === version),
);
const editorManifest = JSON.parse(text("editors/vscode/package.json"));
check(
  "VS Code extension uses a valid independent 0.8 version",
  /^0\.8\.\d+$/.test(editorManifest.version),
);
check(
  "standalone realtime package exists",
  existsSync(join(root, "packages/realtime/src/index.ts")) &&
    existsSync(join(root, "packages/realtime/components/RealtimeRoom.wrn")),
);
check(
  "auth provides helper and UI block kits",
  existsSync(join(root, "packages/auth/src/helpers.ts")) &&
    existsSync(join(root, "packages/auth/components/AuthShell.wrn")) &&
    has("packages/auth/package.json", '"@wrnexus/ui": "workspace:*"'),
);
check(
  "captcha provides helper and UI wrapper kits",
  existsSync(join(root, "packages/captcha/src/helpers.ts")) &&
    existsSync(join(root, "packages/captcha/components/CaptchaField.wrn")),
);
check(
  "database repository helpers exist",
  has("packages/db/src/helpers.ts", "createRepository") &&
    has("packages/db/src/helpers.ts", "retryTransaction"),
);
check(
  "database repositories use dialect-aware placeholders",
  has("packages/db/src/helpers.ts", 'dialect === "postgres" ? `$${index}` : "?"') &&
    has("packages/db/test/helpers.test.ts", "VALUES ($1)"),
);
check(
  "encrypted HTTP envelope is context and replay bound",
  has("packages/encryption/src/http.ts", "WRN-ENCRYPTION-HTTP-REPLAY") &&
    has("packages/encryption/src/http.ts", "payload.path !== normalizePath"),
);
check(
  "encrypted responses are request-id bound and application errors propagate",
  has("packages/encryption/src/http.ts", "expectedRequestId: requestId") &&
    has("packages/encryption/src/http.ts", "const response = await next();"),
);
check(
  "encryption documentation preserves HTTPS boundary",
  has("packages/encryption/README.md", /TLS|HTTPS/) &&
    has("packages/encryption/README.md", /browser|end user/i),
);
check(
  "JWT access, refresh, scope, cookie, and pair helpers exist",
  [
    "createAccessToken",
    "createRefreshToken",
    "requireScopes",
    "jwtCookie",
    "readJwtCookie",
    "createTokenPair",
  ].every((name) => has("packages/jwt/src/helpers.ts", name)),
);
check(
  "i18n supports nested locales and quality negotiation",
  has("packages/i18n/src/index.ts", "localeFiles") &&
    has("packages/i18n/src/index.ts", "parseAcceptLanguage"),
);
check(
  "i18n safely resolves namespace collisions and wildcard language ranges",
  has("packages/i18n/src/index.ts", 'tag?.trim() === "*"') &&
    has("packages/i18n/test/package-kit.test.ts", "primitive namespace collisions"),
);
check(
  "i18n runtime data is injected into rendered documents",
  has("packages/dev-server/src/runtime.ts", "renderI18nData(deps.i18n, language)") &&
    has("packages/dev-server/src/runtime.ts", "deps.i18n.cookie.name"),
);
check(
  "image package provides picture, loaders, placeholder, and preload helpers",
  ["createPicture", "createCdnImageLoader", "createBlurPlaceholder", "imagePreload"].every((name) =>
    has("packages/image/src/index.ts", name),
  ),
);
check(
  "image helpers validate finite dimensions and preserve URL fragments",
  has("packages/image/src/index.ts", "Image width bounds must be finite") &&
    has("packages/image/test/package-kit.test.ts", "URL fragments"),
);
check(
  "realtime messages are size, room, type, and payload bounded",
  has("packages/realtime/src/messages.ts", "maxBytes") &&
    has("packages/realtime/src/messages.ts", "Unsafe realtime payload key"),
);
check(
  "auth shell uses statically discoverable Tailwind width classes",
  !has("packages/auth/components/AuthShell.wrn", "max-w-{maxWidth}") &&
    has("packages/auth/components/AuthShell.wrn", "class:max-w-md"),
);
check(
  "uploader package provides UI blocks and helpers",
  existsSync(join(root, "packages/uploader/components/UploadDropzone.wrn")) &&
    existsSync(join(root, "packages/uploader/src/helpers.ts")),
);
check(
  "validation package provides UI blocks and helpers",
  existsSync(join(root, "packages/validation/components/ValidationSummary.wrn")) &&
    existsSync(join(root, "packages/validation/src/helpers.ts")),
);
check(
  "validation schemas infer helper output types",
  has("packages/validation/src/index.ts", "export type InferSchema") &&
    has("packages/validation/src/helpers.ts", "schema: ObjectSchema<T>") &&
    has("packages/validation/test/helpers.test.ts", "const email: string = value.email"),
);
check(
  "validation oneOf preserves literal union types",
  has("packages/validation/src/index.ts", "class StringSchema<TValue extends string") &&
    has("packages/validation/src/index.ts", "TValues extends readonly [string, ...string[]]") &&
    has("packages/validation/test/helpers.test.ts", "const schema: ObjectSchema<ContactInput>"),
);
check(
  `current ${releaseVersion} migration exists`,
  has("packages/cli/src/update.ts", `version: ${JSON.stringify(releaseVersion)}`),
);
check(
  "package kit audit exists",
  existsSync(join(root, "scripts/audit-package-kits.mjs")) &&
    rootManifest.scripts?.["audit:packages"] === "node scripts/audit-package-kits.mjs",
);
check(
  "audit validators are read-only and reports use explicit generators",
  rootManifest.scripts?.["security:framework"] === "node scripts/security-performance-audit.mjs" &&
    rootManifest.scripts?.["generate:security-report"] ===
      "node scripts/security-performance-audit.mjs --write" &&
    rootManifest.scripts?.["generate:package-audit"] ===
      "node scripts/audit-package-kits.mjs --write" &&
    has("scripts/security-performance-audit.mjs", 'process.argv.includes("--write")') &&
    has("scripts/audit-package-kits.mjs", 'process.argv.includes("--write")'),
);
const publicApi = spawnSync(process.execPath, ["scripts/check-public-api.mjs"], {
  cwd: root,
  encoding: "utf8",
});
if (publicApi.stdout) process.stdout.write(publicApi.stdout);
if (publicApi.stderr) process.stderr.write(publicApi.stderr);
check(
  "public package exports match the reviewed API baseline",
  publicApi.status === 0 && existsSync(join(root, "docs/public-api-0.8.json")),
);
const audit = spawnSync(process.execPath, ["scripts/audit-package-kits.mjs"], {
  cwd: root,
  encoding: "utf8",
});
if (audit.stdout) process.stdout.write(audit.stdout);
if (audit.stderr) process.stderr.write(audit.stderr);
check("all package kits pass the executable audit", audit.status === 0);
const runtimeProbe = spawnSync(
  process.execPath,
  ["--experimental-transform-types", "scripts/test-package-kits.mjs"],
  { cwd: root, encoding: "utf8" },
);
if (runtimeProbe.stdout) process.stdout.write(runtimeProbe.stdout);
if (runtimeProbe.stderr) process.stderr.write(runtimeProbe.stderr);
check("package helper runtime probes pass", runtimeProbe.status === 0);
check(
  "package helper APIs have dedicated tests",
  [
    "packages/encryption/test/http.test.ts",
    "packages/jwt/test/helpers.test.ts",
    "packages/db/test/helpers.test.ts",
    "packages/i18n/test/package-kit.test.ts",
    "packages/image/test/package-kit.test.ts",
    "packages/captcha/test/helpers.test.ts",
    "packages/uploader/test/helpers.test.ts",
    "packages/validation/test/helpers.test.ts",
    "packages/realtime/test/realtime.test.ts",
    "packages/auth/test/package-components.test.ts",
  ].every((path) => existsSync(join(root, path))),
);
console.log(`\n${passed} passed`);
console.log(`${failed} failed`);
if (failed) {
  console.error("\nFailures:");
  for (const value of failures) console.error(`- ${value}`);
  process.exitCode = 1;
}
