#!/usr/bin/env node

import { readdir, readFile, realpath } from "node:fs/promises";
import { dirname, relative, resolve, sep } from "node:path";

const rootArgument = process.argv[2];
if (!rootArgument) throw new Error("usage: build_legacy_project_manifest.mjs <legacy-workspaces-root>");
const root = await realpath(rootArgument);
const projectFiles = await findProjectFiles(root);
const seenIds = new Set();
const manifest = [];
for (const projectFile of projectFiles) {
  const metadata = JSON.parse(await readFile(projectFile, "utf8"));
  if (typeof metadata.id !== "string" || metadata.id.trim() === "") {
    throw new Error(`project metadata has no id: ${projectFile}`);
  }
  if (seenIds.has(metadata.id)) throw new Error(`duplicate project id: ${metadata.id}`);
  seenIds.add(metadata.id);
  if (typeof metadata.name !== "string" || metadata.name.trim() === "") {
    throw new Error(`project metadata has no name: ${projectFile}`);
  }
  const projectRoot = dirname(projectFile);
  const sourceRelativePath = relative(root, projectRoot).split(sep).join("/");
  const physicalFolderPath = dirname(sourceRelativePath) === "."
    ? []
    : dirname(sourceRelativePath).split("/");
  if (metadata.folderPath !== undefined && (
    !Array.isArray(metadata.folderPath)
    || metadata.folderPath.some((part) => typeof part !== "string")
    || JSON.stringify(metadata.folderPath) !== JSON.stringify(physicalFolderPath)
  )) {
    process.stderr.write(`[legacy-manifest] stale metadata folderPath; using physical path: ${projectFile}\n`);
  }
  manifest.push({
    legacyId: metadata.id,
    name: metadata.name,
    folderPath: physicalFolderPath,
    sourceRelativePath,
  });
}
manifest.sort((left, right) => left.sourceRelativePath.localeCompare(right.sourceRelativePath, "zh-CN"));
process.stdout.write(`${JSON.stringify(manifest, null, 2)}\n`);

async function findProjectFiles(directory) {
  const entries = await readdir(directory, { withFileTypes: true });
  const projectMetadata = entries.find((entry) => entry.isFile() && entry.name === "project.json");
  if (projectMetadata !== undefined) return [resolve(directory, projectMetadata.name)];
  const found = [];
  for (const entry of entries) {
    if (entry.name === ".trash") continue;
    const path = resolve(directory, entry.name);
    if (entry.isSymbolicLink()) {
      process.stderr.write(`[legacy-manifest] skip untracked symbolic link: ${path}\n`);
      continue;
    }
    if (entry.isDirectory()) found.push(...await findProjectFiles(path));
  }
  return found;
}
