/**
 * Claude Code CLI Extension
 *
 * Registers a tool that runs prompts through the Claude Code CLI.
 * Pipes the prompt via stdin to avoid shell escaping issues.
 *
 * Requirements:
 *   - Claude Code CLI installed and on PATH (`claude`)
 */

import { Type } from '@sinclair/typebox';
import { spawn } from 'node:child_process';
import type { ExtensionAPI } from 'shortcutxl/app';

export default function (shortcut: ExtensionAPI) {
  shortcut.registerTool({
    name: 'claude_code',
    label: 'Claude Code',
    description:
      "Run a prompt through the Claude Code CLI (claude). Use for complex coding tasks, multi-file edits, research, or any task that benefits from a separate agentic coding session. The CLI has full filesystem and shell access. Returns Claude Code's text output.",
    parameters: Type.Object({
      prompt: Type.String({ description: 'The prompt/instruction to send to Claude Code CLI' }),
      cwd: Type.Optional(
        Type.String({
          description: 'Working directory for the command. Defaults to current directory.'
        })
      )
    }),
    async execute(_toolCallId, params, signal) {
      const { prompt, cwd } = params;

      return new Promise((resolve) => {
        const child = spawn('bash', ['-c', 'claude -p --output-format text'], {
          cwd: cwd || process.cwd(),
          stdio: ['pipe', 'pipe', 'pipe']
        });

        // Pipe prompt via stdin to avoid shell escaping
        child.stdin.write(prompt);
        child.stdin.end();

        let stdout = '';
        let stderr = '';
        child.stdout.on('data', (d: Buffer) => {
          stdout += d.toString();
        });
        child.stderr.on('data', (d: Buffer) => {
          stderr += d.toString();
        });

        const timer = setTimeout(() => child.kill(), 300_000);
        const onAbort = () => {
          child.kill();
          clearTimeout(timer);
        };
        signal?.addEventListener('abort', onAbort, { once: true });

        child.on('close', (code) => {
          clearTimeout(timer);
          signal?.removeEventListener('abort', onAbort);

          if (code !== 0 && !stdout.trim()) {
            resolve({
              content: [{ type: 'text', text: `Exit code ${code}\n${stderr}` }],
              details: { error: true }
            });
          } else {
            const output = stdout.trim() + (stderr.trim() ? `\n[stderr]: ${stderr.trim()}` : '');
            resolve({
              content: [{ type: 'text', text: output || '(no output)' }],
              details: {}
            });
          }
        });
      });
    }
  });
}
