import { readFile } from 'node:fs/promises';

import { Command } from 'commander';
import pc from 'picocolors';
import { parse } from 'yaml';

import { executePrompt } from '../lib/runner.js';
import { readStdin } from '../lib/stdin.js';
import {
  getTemplate,
  saveTemplate,
  listTemplates,
  deleteTemplate,
  renderTemplate,
} from '../lib/template-store.js';
import type { TemplateDefinition } from '../lib/types.js';

/** Create the `dproxy template` Commander command with list/show/add/run/delete subcommands. */
export function createTemplateCommand(): Command {
  const cmd = new Command('template').description('Manage prompt templates');

  cmd
    .command('list')
    .description('List all templates')
    .action(async () => {
      const templates = await listTemplates();
      if (templates.length === 0) {
        console.log(pc.dim("No templates. Use 'dproxy template add <name>' to create one."));
        return;
      }
      for (const t of templates) {
        const desc = t.description ? pc.dim(` — ${t.description}`) : '';
        console.log(`${pc.blue(t.name)}${desc}`);
      }
    });

  cmd
    .command('show <name>')
    .description('Show template details')
    .action(async (name: string) => {
      const t = await getTemplate(name);
      if (!t) {
        console.error(pc.red(`Template "${name}" not found.`));
        process.exit(1);
      }
      console.log(pc.bold(t.name));
      if (t.description) console.log(pc.dim(t.description));
      console.log();
      console.log(pc.bold('Prompt:'));
      console.log(t.prompt);
      if (t.variables?.length) {
        console.log();
        console.log(pc.bold('Variables:'));
        for (const v of t.variables) {
          const req = v.required ? pc.red('*') : '';
          const def = v.default ? pc.dim(` (default: ${v.default})`) : '';
          const src = v.source ? pc.dim(` [${v.source}]`) : '';
          console.log(`  {{${v.name}}}${req}${def}${src}`);
        }
      }
    });

  cmd
    .command('add <name>')
    .description('Add a template from a YAML file or interactively')
    .option('-f, --file <path>', 'Import from YAML file')
    .option('-d, --description <text>', 'Template description')
    .option('-p, --prompt <text>', 'Template prompt text')
    .action(async (name: string, opts) => {
      let template: TemplateDefinition;

      if (opts.file) {
        const raw = await readFile(opts.file, 'utf-8');
        template = parse(raw) as TemplateDefinition;
        template.name = name;
      } else if (opts.prompt) {
        template = {
          name,
          description: opts.description,
          prompt: opts.prompt,
        };
      } else {
        console.error(pc.red('Provide --file or --prompt'));
        process.exit(1);
      }

      await saveTemplate(template);
      console.log(pc.green(`Template "${name}" saved.`));
    });

  cmd
    .command('run <name>')
    .description('Run a template')
    .option('--var <pairs...>', 'Variables as key=value pairs')
    .option('-m, --model <model>', 'Model override')
    .option('--raw', 'Print raw JSON response')
    .action(async (name: string, opts) => {
      const t = await getTemplate(name);
      if (!t) {
        console.error(pc.red(`Template "${name}" not found.`));
        process.exit(1);
      }

      // Parse variables
      const vars: Record<string, string> = {};
      if (opts.var) {
        for (const pair of opts.var as string[]) {
          const eq = pair.indexOf('=');
          if (eq === -1) continue;
          vars[pair.slice(0, eq)] = pair.slice(eq + 1);
        }
      }

      // Check for stdin variable
      const stdinVar = t.variables?.find((v) => v.source === 'stdin');
      if (stdinVar) {
        const stdinContent = await readStdin();
        if (stdinContent) {
          vars[stdinVar.name] = stdinContent;
        }
      }

      // Apply defaults
      if (t.variables) {
        for (const v of t.variables) {
          if (!(v.name in vars) && v.default) {
            vars[v.name] = v.default;
          }
          if (v.required && !(v.name in vars)) {
            console.error(pc.red(`Missing required variable: {{${v.name}}}`));
            process.exit(1);
          }
        }
      }

      const rendered = renderTemplate(t, vars);

      const result = await executePrompt(rendered, {
        model: (opts.model as string) ?? t.claudeOptions?.model,
        maxTurns: t.claudeOptions?.maxTurns,
        maxBudgetUsd: t.claudeOptions?.maxBudgetUsd,
      });

      if (opts.raw) {
        console.log(JSON.stringify(result.raw ?? result, null, 2));
      } else {
        console.log(result.text);
      }
    });

  cmd
    .command('delete <name>')
    .description('Delete a template')
    .action(async (name: string) => {
      const deleted = await deleteTemplate(name);
      if (deleted) {
        console.log(pc.green(`Template "${name}" deleted.`));
      } else {
        console.error(pc.red(`Template "${name}" not found.`));
      }
    });

  return cmd;
}
