import type { Plugin } from 'vite';
import { spawn } from 'node:child_process';
import { commandExists, decodeOutput, getSpawnCommandSpec } from '../scripts/utils/command-runtime.mjs';

type AIType = 'claude' | 'gemini' | 'opencode' | 'cursor' | 'codex';

interface RunAIOptions {
  cli: AIType;
  prompt: string;
  silent?: boolean;
  interactive?: boolean;
}

/**
 * 检测 CLI 是否存在
 */
function hasCommand(cmd: string): boolean {
  return commandExists(cmd);
}

type CliSpawnConfig = {
  command: string;
  args: string[];
  useStdin: boolean;
  input?: string;
};

/**
 * CLI 适配器（严格对齐官方用法）
 */
const CLI_ADAPTERS: Record<AIType, (opts: RunAIOptions) => CliSpawnConfig> = {
  claude: ({ prompt, interactive }) => {
    if (interactive) {
      // 官方：claude [prompt] → 启动交互式会话，并把 prompt 作为首条消息
      return { command: 'claude', args: [prompt], useStdin: false };
    }
    // 官方 headless 模式
    return { command: 'claude', args: ['-p', prompt], useStdin: false };
  },
  gemini: ({ prompt, interactive }) => {
    if (interactive) {
      // 官方：gemini -i "<prompt>" → 执行 prompt 并进入交互模式
      return { command: 'gemini', args: ['-i', prompt], useStdin: false };
    }
    // Gemini CLI 通过 stdin 接收输入
    return { command: 'gemini', args: [], useStdin: true, input: prompt };
  },
  opencode: ({ prompt, interactive }) => {
    if (interactive) {
      // 启动 OpenCode TUI，并附带首条 prompt（如 CLI 版本不支持该参数，会在运行时报错）
      return { command: 'opencode', args: ['--prompt', prompt], useStdin: false };
    }
    // 非交互模式：opencode run "prompt"
    return { command: 'opencode', args: ['run', prompt], useStdin: false };
  },
  cursor: ({ prompt, interactive }) => {
    if (interactive) {
      // 启动 Cursor Agent 交互式会话
      return { command: 'agent', args: [prompt], useStdin: false };
    }
    // 非交互模式（打印模式）：agent -p "prompt" --output-format text
    return { command: 'agent', args: ['-p', prompt, '--output-format', 'text'], useStdin: false };
  },
  codex: ({ prompt, interactive }) => {
    if (interactive) {
      // 启动 Codex 交互式 TUI
      return { command: 'codex', args: [prompt], useStdin: false };
    }
    // 非交互模式：codex exec "prompt" --full-auto
    // --full-auto: 低摩擦自动化模式（workspace-write sandbox + on-request approvals）
    return { command: 'codex', args: ['exec', prompt, '--full-auto'], useStdin: false };
  },
};

function spawnAIProcess(options: RunAIOptions) {
  const {
    cli,
    prompt,
    silent = false,
    interactive = false,
  } = options;

  // Cursor 使用 'agent' 命令，需要特殊检测
  const commandToCheck = cli === 'cursor' ? 'agent' : cli;
  if (!hasCommand(commandToCheck)) {
    throw new Error(`CLI not found: ${cli} (command: ${commandToCheck})`);
  }

  // 交互式 → 强制非静默（否则用户看不到 TUI）
  const finalSilent = interactive ? false : silent;

  const adapter = CLI_ADAPTERS[cli];
  if (!adapter) {
    throw new Error(`Unsupported CLI: ${cli}`);
  }

  const config = adapter({ ...options, interactive });
  const { command, args, useStdin, input } = config;

  console.log(
    `[AI CLI] Spawning command: ${command} ${args.join(' ')}${useStdin ? ' (with stdin)' : ''}`,
  );

  const spawnSpec = getSpawnCommandSpec(command, args);
  const child = spawn(spawnSpec.command, spawnSpec.args, {
    stdio: finalSilent
      ? ['pipe', 'pipe', 'pipe']
      : (useStdin ? ['pipe', 'inherit', 'inherit'] : 'inherit'),
    env: process.env,
    shell: false,
    windowsHide: spawnSpec.windowsHide,
  });

  // 如果需要通过 stdin 传递输入
  if (useStdin && input && child.stdin) {
    console.log(`[AI CLI] Writing to stdin: ${input.substring(0, 50)}...`);
    child.stdin.write(input);
    child.stdin.end();
  }

  return { child, finalSilent };
}

/**
 * 统一执行入口
 */
function runAICommand(options: RunAIOptions): Promise<string> {
  return new Promise<string>((resolve, reject) => {
    const { child, finalSilent } = spawnAIProcess(options);

    let output = '';
    let errorOutput = '';

    // 仅在非交互模式下设置超时（交互式会话不应被强制终止）
    const timeoutMs = options.interactive ? 0 : 60000;
    const timeout = timeoutMs
      ? setTimeout(() => {
        console.error(`[AI CLI] Command timeout after ${Math.round(timeoutMs / 1000)}s`);
        child.kill('SIGTERM');
        reject(new Error(`Command execution timeout (${Math.round(timeoutMs / 1000)}s)`));
      }, timeoutMs)
      : null;

    // 捕获输出
    if (finalSilent && child.stdout && child.stderr) {
      child.stdout.on('data', (data) => {
        const chunk = decodeOutput(data);
        output += chunk;
        console.log(`[AI CLI] stdout chunk: ${chunk.substring(0, 100)}${chunk.length > 100 ? '...' : ''}`);
      });

      child.stderr.on('data', (data) => {
        const chunk = decodeOutput(data);
        errorOutput += chunk;
        console.error(`[AI CLI] stderr chunk: ${chunk.substring(0, 100)}${chunk.length > 100 ? '...' : ''}`);
      });
    }

    // 错误处理
    child.on('error', (error) => {
      if (timeout) clearTimeout(timeout);
      console.error(`[AI CLI] Process error:`, error);
      reject(error);
    });

    // 进程关闭 - 这是主要的完成事件
    child.on('close', (code, signal) => {
      if (timeout) clearTimeout(timeout);
      console.log(`[AI CLI] Process closed with code ${code}, signal ${signal}`);
      
      if (code === 0) {
        const result = output.trim() || errorOutput.trim() || 'Command executed successfully';
        console.log(`[AI CLI] Success, output length: ${result.length}`);
        resolve(result);
      } else {
        const errorMsg = `CLI exited with code ${code}${signal ? ` (signal: ${signal})` : ''}\nOutput: ${output}\nError: ${errorOutput}`;
        console.error(`[AI CLI] Failed:`, errorMsg);
        reject(new Error(errorMsg));
      }
    });
  });
}

/**
 * AI CLI Plugin
 * Provides API endpoints for executing local AI CLI commands (Claude, Gemini)
 */
export function aiCliPlugin(): Plugin {
  // 防抖机制：记录正在执行的任务
  const runningTasks = new Map<string, { promise: Promise<string>; timestamp: number }>();
  const DEBOUNCE_TIME = 2000; // 2秒内的相同请求会被合并
  let interactiveSession:
    | { pid: number; cli: AIType; startedAt: number }
    | null = null;

  return {
    name: 'ai-cli-api',

    configureServer(server) {
      // Helper functions
      const sendJSON = (res: any, statusCode: number, data: any) => {
        res.statusCode = statusCode;
        res.setHeader('Content-Type', 'application/json; charset=utf-8');
        res.end(JSON.stringify(data));
      };

      const sendError = (res: any, statusCode: number, message: string) => {
        sendJSON(res, statusCode, { 
          error: message, 
          timestamp: new Date().toISOString() 
        });
      };

      // 生成任务唯一标识
      const getTaskKey = (cli: string, prompt: string): string => {
        return `${cli}:${prompt}`;
      };

      // 清理过期任务
      const cleanupExpiredTasks = () => {
        const now = Date.now();
        for (const [key, task] of runningTasks.entries()) {
          if (now - task.timestamp > DEBOUNCE_TIME) {
            runningTasks.delete(key);
          }
        }
      };

      // Middleware to handle API routes
      server.middlewares.use(async (req, res, next) => {
        const url = req.url || '';

        // GET /api/ai/execute - Execute AI CLI command
        if (url.startsWith('/api/ai/execute') && req.method === 'GET') {
          try {
            const urlObj = new URL(url, `http://${req.headers.host}`);
            const cli = urlObj.searchParams.get('cli') as AIType;
            const prompt = urlObj.searchParams.get('prompt');
            const silent = urlObj.searchParams.get('silent') !== 'false'; // 默认 true
            const interactive = urlObj.searchParams.get('interactive') === 'true'; // 默认 false

            // Validate required fields
            if (!cli || !['claude', 'gemini', 'opencode', 'cursor', 'codex'].includes(cli)) {
              return sendError(res, 400, 'Invalid or missing "cli" parameter. Must be "claude", "gemini", "opencode", "cursor", or "codex"');
            }

            if (!prompt || typeof prompt !== 'string') {
              return sendError(res, 400, 'Invalid or missing "prompt" parameter');
            }

            // Check if CLI is available
            const commandToCheck = cli === 'cursor' ? 'agent' : cli;
            if (!hasCommand(commandToCheck)) {
              return sendError(res, 404, `CLI not found: ${cli}. Please install it first.`);
            }

            // 交互式会话：直接在 dev server 的终端里启动 TUI，不等待结束（避免 HTTP 长连接挂起）
            if (interactive) {
              if (interactiveSession) {
                return sendError(
                  res,
                  409,
                  `Interactive session already running (cli: ${interactiveSession.cli}, pid: ${interactiveSession.pid}). Please exit it before starting a new one.`,
                );
              }

              console.log(`[AI CLI] Launching interactive ${cli} session...`);

              try {
                const { child } = spawnAIProcess({
                  cli,
                  prompt,
                  silent: false,
                  interactive: true,
                });

                interactiveSession = {
                  pid: child.pid ?? -1,
                  cli,
                  startedAt: Date.now(),
                };

                child.on('close', () => {
                  interactiveSession = null;
                });

                sendJSON(res, 202, {
                  success: true,
                  cli,
                  interactive: true,
                  pid: child.pid ?? null,
                  message: 'Interactive session started in the dev server terminal.',
                  timestamp: new Date().toISOString(),
                });
              } catch (error: any) {
                console.error('[AI CLI] Interactive launch error:', error);
                interactiveSession = null;
                sendError(res, 500, error.message || 'Failed to launch interactive AI CLI session');
              }

              return;
            }

            // 防抖检查
            cleanupExpiredTasks();
            const taskKey = getTaskKey(cli, prompt);
            const existingTask = runningTasks.get(taskKey);

            if (existingTask) {
              console.log(`[AI CLI] Reusing existing task for ${cli}:`, prompt.substring(0, 50) + '...');
              try {
                const result = await existingTask.promise;
                sendJSON(res, 200, {
                  success: true,
                  cli,
                  output: result || 'Command executed successfully',
                  cached: true,
                  timestamp: new Date().toISOString(),
                });
              } catch (error: any) {
                console.error('[AI CLI] Cached task error:', error);
                sendError(res, 500, error.message || 'Failed to execute AI CLI command');
              }
              return;
            }

            console.log(`[AI CLI] Executing ${cli} command:`, { 
              prompt: prompt.substring(0, 50) + '...', 
              silent, 
              interactive 
            });

            // 创建新任务
            const taskPromise = runAICommand({
              cli,
              prompt,
              silent,
              interactive,
            });

            // 记录任务
            runningTasks.set(taskKey, {
              promise: taskPromise,
              timestamp: Date.now(),
            });

            // 执行任务
            try {
              const result = await taskPromise;
              sendJSON(res, 200, {
                success: true,
                cli,
                output: result || 'Command executed successfully',
                cached: false,
                timestamp: new Date().toISOString(),
              });
            } catch (error: any) {
              console.error('[AI CLI] Execution error:', error);
              sendError(res, 500, error.message || 'Failed to execute AI CLI command');
            } finally {
              // 延迟删除任务，允许短时间内的重复请求复用结果
              setTimeout(() => {
                runningTasks.delete(taskKey);
              }, DEBOUNCE_TIME);
            }
          } catch (error: any) {
            console.error('[AI CLI] Request handling error:', error);
            sendError(res, 500, error.message || 'Internal server error');
          }
          return;
        }

        // GET /api/ai/status - Check CLI availability
        if (url.startsWith('/api/ai/status') && req.method === 'GET') {
          try {
            const status = {
              claude: hasCommand('claude'),
              gemini: hasCommand('gemini'),
              opencode: hasCommand('opencode'),
              cursor: hasCommand('agent'), // Cursor CLI 使用 'agent' 命令
              codex: hasCommand('codex'),
              runningTasks: runningTasks.size,
              timestamp: new Date().toISOString(),
            };

            sendJSON(res, 200, status);
          } catch (error: any) {
            console.error('[AI CLI] Status check error:', error);
            sendError(res, 500, error.message || 'Failed to check CLI status');
          }
          return;
        }

        next();
      });
    }
  };
}
