import { mkdirSync, readdirSync, statSync, writeFileSync } from "node:fs";
import { dirname, join, relative } from "node:path";

const repoRoot = new URL("..", import.meta.url).pathname;
const catalogsRoot = join(repoRoot, "catalogs");
const output = join(repoRoot, "src", "generated", "bundled-catalogs.ts");

const catalogDirs = readdirSync(catalogsRoot)
  .map((name) => join(catalogsRoot, name))
  .filter((path) => {
    try {
      return statSync(join(path, "manifest.json")).isFile();
    } catch {
      return false;
    }
  })
  .sort();

// Per-catalog discovery: the manifest at <dir>/manifest.json plus any
// migration-vN-to-v(N+1).json files. Migration files travel with the
// catalog so the local-boot path can apply major-version upgrades to
// already-installed worlds without going through the GitHub tap.
let importIndex = 0;
const importLines = [];
const entryLines = [];
for (const dir of catalogDirs) {
  const manifestPath = join(dir, "manifest.json");
  const manifestVar = `manifest${importIndex++}`;
  importLines.push(
    `import ${manifestVar} from "${importPath(manifestPath)}";`
  );
  const migrationFiles = readdirSync(dir)
    .filter((name) => /^migration-v\d+-to-v\d+\.json$/.test(name))
    .sort();
  const migrationVars = [];
  for (const name of migrationFiles) {
    const v = `migration${importIndex++}`;
    importLines.push(
      `import ${v} from "${importPath(join(dir, name))}";`
    );
    migrationVars.push(v);
  }
  const fromRoot = relative(repoRoot, manifestPath).replaceAll("\\", "/");
  const migrationsExpr = migrationVars.length === 0
    ? "[]"
    : `[${migrationVars.map((v) => `${v} as unknown as CatalogMigrationManifest`).join(", ")}]`;
  entryLines.push(
    `  { path: ${JSON.stringify(fromRoot)}, manifest: ${manifestVar} as unknown as CatalogManifest, migrations: ${migrationsExpr} }`
  );
}

function importPath(absPath) {
  const fromOutput = relative(join(repoRoot, "src", "generated"), absPath).replaceAll("\\", "/");
  return fromOutput.startsWith(".") ? fromOutput : `./${fromOutput}`;
}

mkdirSync(dirname(output), { recursive: true });

writeFileSync(output, `// Generated by scripts/generate-bundled-catalog-index.mjs.
// Do not hand-edit. Bundled catalogs are discovered from catalogs/*/manifest.json,
// and any migration-vN-to-v(N+1).json files in the catalog directory.

import type { CatalogManifest, CatalogMigrationManifest } from "../core/catalog-installer";
${importLines.join("\n")}

export type BundledCatalogEntry = {
  readonly path: string;
  readonly manifest: CatalogManifest;
  readonly migrations: readonly CatalogMigrationManifest[];
};

export const BUNDLED_CATALOGS: readonly BundledCatalogEntry[] = [
${entryLines.join(",\n")}
];
`);
