/**
 * Command 执行器
 *
 * 负责解析和执行 Command：
 * - 参数替换（$ARGUMENTS, $1, $2, ...）
 * - 文件引用（@filepath）
 * - Shell 命令执行（!`command`）
 */

import * as fs from 'fs/promises';
import * as path from 'path';
import { exec } from 'child_process';
import { promisify } from 'util';
import type { Command, CommandInput, CommandExecutionResult } from './types.js';
import { getCommandRegistry } from './registry.js';

const execAsync = promisify(exec);

/**
 * Command 执行器
 */
export class CommandExecutor {
  private workdir: string;

  constructor(workdir: string = process.cwd()) {
    this.workdir = workdir;
  }

  /**
   * 解析用户输入的命令字符串
   * 例如: "/review main..feature" → { command: "review", arguments: "main..feature", args: ["main..feature"] }
   */
  parseInput(input: string): CommandInput | null {
    // 移除开头的 /
    const trimmed = input.trim();
    if (!trimmed.startsWith('/')) {
      return null;
    }

    const withoutSlash = trimmed.slice(1);
    const spaceIndex = withoutSlash.indexOf(' ');

    let commandName: string;
    let argumentsStr: string;

    if (spaceIndex === -1) {
      commandName = withoutSlash;
      argumentsStr = '';
    } else {
      commandName = withoutSlash.slice(0, spaceIndex);
      argumentsStr = withoutSlash.slice(spaceIndex + 1).trim();
    }

    // 解析参数数组
    const args = argumentsStr ? this.parseArgs(argumentsStr) : [];

    return {
      command: commandName,
      arguments: argumentsStr,
      args,
      workdir: this.workdir,
    };
  }

  /**
   * 解析参数字符串为数组
   * 支持引号包裹的参数
   */
  private parseArgs(argsStr: string): string[] {
    const args: string[] = [];
    let current = '';
    let inQuote = false;
    let quoteChar = '';

    for (const char of argsStr) {
      if ((char === '"' || char === "'") && !inQuote) {
        inQuote = true;
        quoteChar = char;
      } else if (char === quoteChar && inQuote) {
        inQuote = false;
        quoteChar = '';
      } else if (char === ' ' && !inQuote) {
        if (current) {
          args.push(current);
          current = '';
        }
      } else {
        current += char;
      }
    }

    if (current) {
      args.push(current);
    }

    return args;
  }

  /**
   * 执行 Command
   */
  async execute(input: CommandInput): Promise<CommandExecutionResult> {
    const registry = getCommandRegistry();
    const command = registry.get(input.command);

    if (!command) {
      // 尝试搜索相似的 Command
      const suggestions = registry.search(input.command, 3);
      let errorMsg = `Command 不存在: /${input.command}`;

      if (suggestions.length > 0) {
        errorMsg += '\n\n你可能想要的 Command:\n';
        for (const { command: cmd } of suggestions) {
          errorMsg += `- /${cmd.name}`;
          if (cmd.description) {
            errorMsg += `: ${cmd.description}`;
          }
          errorMsg += '\n';
        }
      }

      return {
        success: false,
        error: errorMsg,
      };
    }

    try {
      // 渲染模板
      const prompt = await this.renderTemplate(command.template, input);

      return {
        success: true,
        prompt,
        agent: command.agent,
        model: command.model,
        subtask: command.subtask,
      };
    } catch (error) {
      return {
        success: false,
        error: `Command 执行失败: ${error instanceof Error ? error.message : String(error)}`,
      };
    }
  }

  /**
   * 渲染模板
   */
  async renderTemplate(
    template: string,
    input: CommandInput
  ): Promise<string> {
    let result = template;

    // 1. 替换位置参数 $1, $2, ...
    result = this.replacePositionalArgs(result, input.args);

    // 2. 替换 $ARGUMENTS
    result = result.replace(/\$ARGUMENTS/g, input.arguments);

    // 3. 处理文件引用 @filepath
    result = await this.resolveFileReferences(result, input.workdir);

    // 4. 执行 Shell 命令 !`command`
    result = await this.executeShellCommands(result, input.workdir);

    return result;
  }

  /**
   * 替换位置参数
   */
  private replacePositionalArgs(template: string, args: string[]): string {
    // 找出模板中使用的最大参数索引
    const paramRegex = /\$(\d+)/g;
    let maxIndex = 0;
    let match;

    while ((match = paramRegex.exec(template)) !== null) {
      const index = parseInt(match[1], 10);
      if (index > maxIndex) {
        maxIndex = index;
      }
    }

    // 替换参数
    let result = template;
    for (let i = 1; i <= maxIndex; i++) {
      const value = i === maxIndex
        ? args.slice(i - 1).join(' ') // 最后一个参数获取剩余所有
        : args[i - 1] || '';

      result = result.replace(new RegExp(`\\$${i}`, 'g'), value);
    }

    return result;
  }

  /**
   * 解析文件引用
   * @filepath → 文件内容
   */
  private async resolveFileReferences(
    template: string,
    workdir: string
  ): Promise<string> {
    const fileRefRegex = /@([^\s]+)/g;
    const matches = [...template.matchAll(fileRefRegex)];

    if (matches.length === 0) {
      return template;
    }

    let result = template;

    for (const match of matches) {
      const [fullMatch, filePath] = match;
      const absolutePath = path.isAbsolute(filePath)
        ? filePath
        : path.join(workdir, filePath);

      try {
        const content = await fs.readFile(absolutePath, 'utf-8');
        // 替换为带有文件路径标记的内容
        const replacement = `\`\`\`${path.extname(filePath).slice(1) || 'txt'}\n// ${filePath}\n${content}\n\`\`\``;
        result = result.replace(fullMatch, replacement);
      } catch (error) {
        // 文件不存在，保留原样或提示
        console.warn(`无法读取文件: ${absolutePath}`);
        result = result.replace(fullMatch, `[文件不存在: ${filePath}]`);
      }
    }

    return result;
  }

  /**
   * 执行 Shell 命令
   * !`command` → 命令输出
   */
  private async executeShellCommands(
    template: string,
    workdir: string
  ): Promise<string> {
    const shellRegex = /!\`([^`]+)\`/g;
    const matches = [...template.matchAll(shellRegex)];

    if (matches.length === 0) {
      return template;
    }

    let result = template;

    for (const match of matches) {
      const [fullMatch, command] = match;

      try {
        const { stdout, stderr } = await execAsync(command, {
          cwd: workdir,
          timeout: 30000, // 30 秒超时
        });

        const output = (stdout + stderr).trim();
        result = result.replace(fullMatch, output);
      } catch (error) {
        // 命令执行失败，替换为错误信息
        const errorMsg = error instanceof Error ? error.message : String(error);
        result = result.replace(fullMatch, `[命令执行失败: ${command}]\n${errorMsg}`);
      }
    }

    return result;
  }
}

/**
 * 创建 Command 执行器
 */
export function createCommandExecutor(
  workdir: string = process.cwd()
): CommandExecutor {
  return new CommandExecutor(workdir);
}
