import { execSync } from "node:child_process";
import search from "@inquirer/search";
import { defineCommand, arg } from "politty";
import { z } from "zod";
import { executeCommand, success, failure, silentFailure } from "../lib/command-result";
import { discoverApps, collectScripts } from "./scripts";

export const runCommand = defineCommand({
  name: "run",
  description: "Interactively select and run an app script",
  args: z.object({
    app: arg(z.string().optional(), {
      positional: true,
      description: "App name (interactive if omitted)",
    }),
    script: arg(z.string().optional(), {
      positional: true,
      description: "Script name (interactive if omitted)",
    }),
  }),
  run: (args) => {
    return executeCommand(async () => {
      const cwd = process.cwd();
      const apps = discoverApps(cwd);
      if (apps.length === 0) {
        return failure("No apps found in apps/");
      }

      let app = args.app;
      if (!app) {
        app = await search({
          message: "Select app:",
          source: (term) => {
            const filtered = term ? apps.filter((a) => a.includes(term)) : apps;
            return filtered.map((a) => ({ name: a, value: a }));
          },
        });
      } else if (!apps.includes(app)) {
        return failure(`App "${app}" not found. Available: ${apps.join(", ")}`);
      }

      const scripts = collectScripts(cwd, app);
      if (scripts.length === 0) {
        return failure(`No scripts found in ${app}`);
      }

      let entry: (typeof scripts)[number];
      if (args.script) {
        const match = scripts.find((s) => s.name === args.script || s.label === args.script);
        if (!match) {
          return failure(
            `Script "${args.script}" not found in ${app}. Available: ${scripts.map((s) => s.label).join(", ")}`,
          );
        }
        entry = match;
      } else {
        entry = await search({
          message: "Select script:",
          source: (term) => {
            const filtered = term ? scripts.filter((s) => s.label.includes(term)) : scripts;
            return filtered.map((s) => ({ name: s.label, value: s }));
          },
        });
      }

      console.log(`\nRunning: pnpm run ${entry.name} (in ${entry.cwd})\n`);
      try {
        execSync(`pnpm run ${entry.name}`, { cwd: entry.cwd, stdio: "inherit" });
        return success();
      } catch (err) {
        const exitCode = (err as { status?: number }).status ?? 1;
        return silentFailure(exitCode);
      }
    });
  },
});
