#!/usr/bin/env node
// file: bin/glide-ui.js
import { Command, InvalidArgumentError } from "commander";
import path from "node:path";
import process from "node:process";
import { fileURLToPath, pathToFileURL } from "node:url";
import { promises as fs } from "node:fs";
import pc from "picocolors";
import {
  discoverAllComponents,
  getComponentInfo,
} from "../dist/cli/component-discovery.js";
import { loadDesignEngineer } from "../dist/cli/component-discovery.js";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// Read package.json version dynamically
const packageJsonPath = path.join(__dirname, "..", "package.json");
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf8"));
const version = packageJson.version;

// --- CLI ---------------------------------------------------------------------
const program = new Command()
  .name("glide-ui")
  .description("Glide UI CLI")
  .version(version);

program
  .command("create:screen")
  .description("Create a new screen from a prompt")
  .option(
    "-p, --prompt <prompt>",
    "The prompt describing the screen to generate",
  )
  .option("-s, --schema <schema>", "Schema for the screen's data (optional)")
  .option(
    "--model <model>",
    "Model to use for code generation (claude-haiku-4-5, gpt-5, v0-1.5-md, etc)",
    "claude-haiku-4-5",
  )
  .option("--json", "Output only JSON to stdout (no logs or banners)", false)
  .option(
    "--validate-code",
    "Enable code validation (ESLint + TypeScript checks)",
    false,
  )
  .action(async (opts) => {
    if (!opts.prompt) {
      console.error(
        pc.red("❌ Error: Prompt is required. Use -p or --prompt to specify."),
      );
      process.exitCode = 1;
      return;
    }

    const model = opts.model || "claude-haiku-4-5";

    const { screenGenerator } = await import("../dist/cli/generate-screen.js");
    const result = await screenGenerator({
      prompt: opts.prompt,
      schema: opts.schema,
      model: model,
      validateCode: opts.validateCode,
    });

    if (opts.json) {
      // --json flag: output only JSON, no other output
      process.stdout.write(JSON.stringify(result, null, 2) + "\n");
    } else {
      // Default: pretty print with some context (for interactive use)
      console.log(JSON.stringify(result, null, 2));
    }
  });

// Get Design Engineer command
program
  .command("design-engineer")
  .description("Get the Design Engineer prompt")
  .action(() => {
    try {
      const designEngineer = loadDesignEngineer();
      console.log(designEngineer);
    } catch (error) {
      console.error(
        pc.red(`❌ Error loading design engineer prompt: ${error.message}`),
      );
    }
  });

// Component commands
program
  .command("components:list")
  .description("List all available components")
  .option("--json", "Output as JSON for LLMs")
  .option("--category <category>", "Filter by category")
  .action((opts) => {
    try {
      const components = discoverAllComponents();

      // Filter by category if specified
      let filtered = components;
      if (opts.category) {
        filtered = components.filter((c) => c.category === opts.category);
      }

      if (opts.json) {
        // JSON output for LLMs
        const output = {
          total: filtered.length,
          categories: [...new Set(filtered.map((c) => c.category))].sort(),
          components: filtered,
        };
        console.log(JSON.stringify(output, null, 2));
      } else {
        // Markdown output (default)
        console.log("# Glide UI Components\n");

        // Group by category
        const grouped = {};
        filtered.forEach((comp) => {
          if (!grouped[comp.category]) {
            grouped[comp.category] = [];
          }
          grouped[comp.category].push(comp);
        });

        Object.entries(grouped)
          .sort()
          .forEach(([category, comps]) => {
            console.log(
              `\n## ${category.charAt(0).toUpperCase() + category.slice(1)}\n`,
            );
            comps.forEach((comp) => {
              const displayName = comp.name;
              const description =
                comp.description || "No description available";
              console.log(`- **${displayName}** (${comp.id}): ${description}`);
            });
          });

        console.log(`\n**Total:** ${filtered.length} components\n`);
      }
    } catch (err) {
      console.error(pc.red(`❌ Error: ${err.message}`));
      process.exitCode = 1;
    }
  });

program
  .command("components:info")
  .description("Get detailed information about components")
  .option(
    "-t, --targets <ids>",
    "Comma-separated list of component ids",
    (value) => value.split(",").map((s) => s.trim()),
  )
  .option("--json", "Output as JSON for LLMs")
  .option(
    "--verbose-props",
    "Show all props individually (includes all event handlers, aria-*, data-*)",
  )
  .action((opts) => {
    try {
      const targets = opts.targets || [];

      if (targets.length === 0) {
        console.error(
          pc.red("❌ Please specify component names using -t or --targets"),
        );
        console.log(
          pc.dim('\nExample: glide-ui components:info -t "button,chrome,list"'),
        );
        console.log(
          pc.dim(
            'Run "glide-ui components:list" to see all available components',
          ),
        );
        process.exitCode = 1;
        return;
      }

      const results = [];
      const notFound = [];

      for (const name of targets) {
        const info = getComponentInfo(name, {
          verbose: opts.verboseProps,
        });
        if (info) {
          results.push(info);
        } else {
          notFound.push(name);
        }
      }

      if (notFound.length > 0) {
        console.error(
          pc.red(`❌ Components not found: ${notFound.join(", ")}`),
        );
        console.log(
          pc.dim(
            '\nRun "glide-ui components:list" to see all available components',
          ),
        );
      }

      if (results.length === 0) {
        process.exitCode = 1;
        return;
      }

      if (opts.json) {
        // JSON output for LLMs
        console.log(JSON.stringify(results, null, 2));
      } else {
        // Markdown output (default)
        console.log("# Component Information\n");

        results.forEach((info, index) => {
          if (index > 0) console.log("\n---\n");

          if (info.type === "group") {
            // Markdown output for grouped components
            console.log(`## ${info.name} Components\n`);
            console.log(`**Import from:** \`${info.importPath}\`\n`);
            console.log("### Available components:\n");

            // Handle components as dictionary
            const componentsArray = Object.entries(info.components).map(
              ([id, comp]) => ({ id, ...comp }),
            );

            componentsArray.forEach((comp) => {
              console.log(`- **${comp.name}** (\`${comp.id}\`)`);
              console.log(`  - Import: \`${comp.import}\``);
              if (comp.description) {
                console.log(
                  `  - Description: ${comp.description.substring(0, 80)}...`,
                );
              }
            });

            console.log(
              `\n**Total:** ${componentsArray.length} components in ${info.name}`,
            );

            // Show full README if available
            if (info.info) {
              console.log("\n---\n");
              console.log(info.info);
            }
          } else {
            // Markdown output for single components
            console.log(`## ${info.name}\n`);
            console.log(`**Category:** ${info.category}`);
            console.log(`**Import:** \`${info.importPath}\`\n`);
            console.log("### Usage:\n");
            console.log("```typescript");
            console.log(info.import);
            console.log("```\n");

            if (info.description) {
              console.log("### Description:\n");
              console.log(info.description + "\n");
            }

            // Show full README if available
            if (info.info) {
              console.log("### Full Documentation:\n");
              console.log(info.info + "\n");
            }

            if (info.props && Object.keys(info.props).length > 0) {
              console.log("### Props:\n");
              console.log("| Prop | Type | Required | Description |");
              console.log("|------|------|----------|-------------|");

              Object.entries(info.props).forEach(([propName, propInfo]) => {
                const type = propInfo.type || "any";
                const required = propInfo.required ? "Yes" : "No";
                const description = propInfo.description || "-";
                console.log(
                  `| \`${propName}\` | \`${type}\` | ${required} | ${description} |`,
                );
              });
              console.log();
            }

            if (info.example) {
              console.log("### Example:\n");
              console.log("```tsx");
              console.log(info.example);
              console.log("```");
            }
          }
        });

        console.log();
      }
    } catch (err) {
      console.error(pc.red(`❌ Error: ${err.message}`));
      process.exitCode = 1;
    }
  });

// Interactive mode (default when no command)
program.action(() => {
  console.log(pc.bold(pc.cyan("\n🎨 Glide UI CLI\n")));
  console.log("Available commands:\n");
  console.log(
    `  ${pc.white("components:list")}              List all available components`,
  );
  console.log(
    `  ${pc.white("components:info")} -t <names>   Get component details`,
  );
  console.log(pc.dim("Examples:"));
  console.log(pc.dim("  npx glide-ui components:list"));
  console.log(pc.dim("  npx glide-ui components:list --json"));
  console.log(pc.dim('  npx glide-ui components:info -t "button"'));
  console.log(pc.dim('  npx glide-ui components:info -t "button,chrome,list"'));
  console.log(
    pc.dim('  npx glide-ui components:info -t "charts/area-chart" --json'),
  );

  console.log(pc.dim('Run "glide-ui <command> --help" for more information\n'));
});

await program.parseAsync(process.argv);
