import fs from "node:fs";
import path from "node:path";
import { z } from "zod";
import { readJsonFile } from "../lib/parse-json";

const PackageJsonScripts = z.object({
  scripts: z.record(z.string(), z.string()).optional(),
});

export interface ScriptEntry {
  name: string;
  label: string;
  cwd: string;
}

export function discoverApps(root: string): string[] {
  const appsDir = path.join(root, "apps");
  if (!fs.existsSync(appsDir)) return [];

  return fs
    .readdirSync(appsDir, { withFileTypes: true })
    .filter((d) => d.isDirectory())
    .map((d) => d.name)
    .sort();
}

function readScripts(pkgPath: string): Record<string, string> {
  if (!fs.existsSync(pkgPath)) return {};
  const result = readJsonFile(pkgPath, PackageJsonScripts);
  if (!result.ok) {
    // A malformed package.json should not abort script discovery for the rest of the app
    console.error(`Warning: skipping ${pkgPath}: ${result.error}`);
    return {};
  }
  return result.data.scripts ?? {};
}

export function collectScripts(root: string, app: string): ScriptEntry[] {
  const appDir = path.join(root, "apps", app);
  const entries: ScriptEntry[] = [];

  // Root package.json
  const rootScripts = readScripts(path.join(appDir, "package.json"));
  for (const name of Object.keys(rootScripts)) {
    entries.push({ name, label: name, cwd: appDir });
  }

  // One-level subdirectory package.json files
  if (!fs.existsSync(appDir)) return entries;
  for (const dirent of fs.readdirSync(appDir, { withFileTypes: true })) {
    if (!dirent.isDirectory() || dirent.name === "node_modules") continue;
    const subDir = path.join(appDir, dirent.name);
    const scripts = readScripts(path.join(subDir, "package.json"));
    for (const name of Object.keys(scripts)) {
      entries.push({ name, label: `${dirent.name} > ${name}`, cwd: subDir });
    }
  }

  return entries;
}
