import { execFileSync } from "node:child_process";
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { dirname, resolve } from "node:path";

import { frozenPackages, frozenRuntime } from "./frozen-versions.mjs";

function readJson(path) {
  return JSON.parse(readFileSync(path, "utf8"));
}

function installedPackage(manifestPath, packageName) {
  const packagePath = resolve(
    dirname(manifestPath),
    "node_modules",
    ...packageName.split("/"),
    "package.json",
  );
  return readJson(packagePath);
}

export function verifyFrozenDependencies() {
  const problems = [];
  const packages = {};

  for (const [manifestPath, sections] of Object.entries(frozenPackages)) {
    const manifest = readJson(manifestPath);
    packages[manifest.name] = {};

    for (const [section, expected] of Object.entries(sections)) {
      for (const [name, version] of Object.entries(expected)) {
        const declared = manifest[section]?.[name];
        if (declared !== version) {
          problems.push(`${manifestPath} ${section}.${name}: declared ${declared ?? "missing"}, expected ${version}`);
          continue;
        }

        const installed = installedPackage(manifestPath, name);
        packages[manifest.name][name] = installed.version;
        if (installed.name !== name) {
          problems.push(`${manifestPath} ${name}: linked package name is ${installed.name ?? "missing"}`);
        } else if (!version.startsWith("workspace:") && installed.version !== version) {
          problems.push(`${manifestPath} ${name}: installed ${installed.version}, expected ${version}`);
        }
      }
    }
  }

  const packageManager = readJson("package.json").packageManager;
  const pnpmVersion = process.platform === "win32"
    ? execFileSync(process.env.ComSpec ?? "cmd.exe", ["/d", "/s", "/c", "pnpm --version"], {
        encoding: "utf8",
      }).trim()
    : execFileSync("pnpm", ["--version"], { encoding: "utf8" }).trim();
  const runtimeChecks = {
    arch: process.arch,
    node: process.version.slice(1),
    os: process.platform,
    packageManager,
    pnpm: pnpmVersion,
  };

  for (const key of ["arch", "node", "os", "pnpm"]) {
    if (runtimeChecks[key] !== frozenRuntime[key]) {
      problems.push(`${key}: running ${runtimeChecks[key]}, expected ${frozenRuntime[key]}`);
    }
  }
  if (packageManager !== `pnpm@${frozenRuntime.pnpm}`) {
    problems.push(`packageManager: declared ${packageManager}, expected pnpm@${frozenRuntime.pnpm}`);
  }

  return {
    packages,
    problems,
    runtime: runtimeChecks,
    status: problems.length === 0 ? "passed" : "failed",
  };
}

const snapshot = verifyFrozenDependencies();
const evidenceDirectory = process.env.DADA_EVIDENCE_DIR;

if (evidenceDirectory) {
  mkdirSync(evidenceDirectory, { recursive: true });
  writeFileSync(
    resolve(evidenceDirectory, "dependency-tree.json"),
    `${JSON.stringify({ schema_version: "1.0", ...snapshot }, null, 2)}\n`,
  );
}

console.log(JSON.stringify(snapshot, null, 2));
if (snapshot.problems.length > 0) process.exit(1);
