import { readdir, readFile, stat } from "node:fs/promises";
import path from "node:path";
import process from "node:process";
import { resolveRealWorkspaceRoot } from "./load-env.mjs";

const rootDir = resolveRealWorkspaceRoot();
const workspaceDirs = ["packages", "tooling"];
const violations = [];

async function pathExists(targetPath) {
  try {
    await stat(targetPath);
    return true;
  } catch {
    return false;
  }
}

async function listPackageJsonFiles(baseDir) {
  const absoluteBaseDir = path.join(rootDir, baseDir);
  if (!(await pathExists(absoluteBaseDir))) {
    return [];
  }

  const entries = await readdir(absoluteBaseDir, { withFileTypes: true });
  return entries
    .filter((entry) => entry.isDirectory())
    .map((entry) => path.join(baseDir, entry.name, "package.json"));
}

function collectExportTargets(value, keyPath, targets) {
  if (typeof value === "string") {
    targets.push({ keyPath, target: value });
    return;
  }

  if (!value || typeof value !== "object") {
    return;
  }

  for (const [key, nestedValue] of Object.entries(value)) {
    collectExportTargets(nestedValue, `${keyPath}.${key}`, targets);
  }
}

function getWildcardBaseDir(target) {
  const wildcardIndex = target.indexOf("*");
  if (wildcardIndex === -1) {
    return target;
  }

  const targetPrefix = target.slice(0, wildcardIndex);
  const lastSlashIndex = targetPrefix.lastIndexOf("/");
  return lastSlashIndex === -1 ? "." : targetPrefix.slice(0, lastSlashIndex);
}

const packageJsonFiles = (
  await Promise.all(workspaceDirs.map((workspaceDir) => listPackageJsonFiles(workspaceDir)))
).flat();

for (const packageJsonFile of packageJsonFiles) {
  const packageJsonPath = path.join(rootDir, packageJsonFile);
  if (!(await pathExists(packageJsonPath))) {
    continue;
  }

  const packageDir = path.dirname(packageJsonPath);
  const packageJson = JSON.parse(await readFile(packageJsonPath, "utf8"));
  const exportsField = packageJson.exports;

  if (!exportsField || typeof exportsField !== "object") {
    continue;
  }

  const exportTargets = [];
  collectExportTargets(exportsField, "exports", exportTargets);

  for (const exportTarget of exportTargets) {
    const exportPath = exportTarget.target;
    const containsWildcard = exportPath.includes("*");
    const relativeCheckPath = containsWildcard ? getWildcardBaseDir(exportPath) : exportPath;
    const absoluteCheckPath = path.resolve(packageDir, relativeCheckPath);
    const relativeFromRoot = path.relative(rootDir, absoluteCheckPath) || ".";

    if (!relativeFromRoot || relativeFromRoot.startsWith("..")) {
      violations.push(
        `${packageJsonFile}: ${exportTarget.keyPath} points outside the repository: ${exportPath}`,
      );
      continue;
    }

    if (!(await pathExists(absoluteCheckPath))) {
      violations.push(
        `${packageJsonFile}: ${exportTarget.keyPath} references a missing path: ${exportPath}`,
      );
    }
  }
}

if (violations.length > 0) {
  console.error("Workspace export check failed:");
  for (const violation of violations) {
    console.error(`- ${violation}`);
  }
  process.exit(1);
}

console.log("Workspace exports passed.");
