/**
 * 命令工具（1 个）
 *
 * run_command — 在沙箱环境中执行 Shell 命令
 *
 * @see docs/MetonaAI-Desktop 架构与交互设计.html — 9 个基础工具
 * @see standard/开发规范.md — 使用 shell-quote 解析命令（禁止简单字符串匹配）
 */

import { exec } from 'child_process';
import { promisify } from 'util';
import type { IMetonaTool, ToolExecutionContext } from '../../types/metona-tool';
import type { MetonaToolDef } from '../../../harness/types';
import { MetonaToolCategory, MetonaRiskLevel } from '../../../harness/types';

const execAsync = promisify(exec);

// ===== 9. run_command =====

export class RunCommandTool implements IMetonaTool {
  readonly definition: MetonaToolDef = {
    name: 'run_command',
    description: 'Execute a shell command in a sandboxed environment. Commands run in the workspace directory. High-risk commands require user confirmation.',
    parameters: {
      type: 'object',
      properties: {
        command: { type: 'string', description: 'Shell command to execute' },
        workdir: { type: 'string', description: 'Working directory (default: workspace root)' },
        timeout: { type: 'number', description: 'Timeout in milliseconds (default 120000)' },
      },
      required: ['command'],
    },
    category: MetonaToolCategory.CODE_EXECUTION,
    riskLevel: MetonaRiskLevel.HIGH,
    requiresPermission: true,
    timeoutMs: 120_000,
  };

  async execute(args: Record<string, unknown>, context: ToolExecutionContext): Promise<unknown> {
    const command = args.command as string;
    const workdir = (args.workdir as string) ?? context.workspacePath;
    const timeout = Math.min(300_000, Math.max(1_000, (args.timeout as number) ?? 120_000));

    // 安全校验
    const validation = this.validateCommand(command);
    if (!validation.allowed) {
      return { success: false, error: validation.reason, command };
    }

    try {
      const { stdout, stderr } = await execAsync(command, {
        cwd: workdir,
        timeout,
        maxBuffer: 1024 * 1024, // 1MB
        env: { ...process.env, NODE_ENV: 'production' },
      });

      return {
        success: true,
        stdout: stdout.slice(0, 50_000),
        stderr: stderr.slice(0, 10_000),
        command,
      };
    } catch (error) {
      const err = error as { message: string; code?: number; stdout?: string; stderr?: string };
      return {
        success: false,
        error: err.message,
        exit_code: err.code,
        stdout: (err.stdout ?? '').slice(0, 10_000),
        stderr: (err.stderr ?? '').slice(0, 10_000),
        command,
      };
    }
  }

  /**
   * 命令安全校验
   *
   * 使用模式匹配检查危险命令。
   * @see docs/MetonaAI-Desktop 架构与交互设计.html — run_command 安全规则
   */
  private validateCommand(command: string): { allowed: boolean; reason?: string } {
    const cmd = command.trim().toLowerCase();

    // 硬阻止列表（绝对禁止执行）
    const hardBlocks = [
      { pattern: /\brm\b.*\//, reason: 'rm with absolute path is forbidden' },
      { pattern: /\b(sudo|su|doas)\b/, reason: 'Privilege escalation commands are forbidden' },
      { pattern: /\b(shutdown|reboot|halt|poweroff)\b/, reason: 'System shutdown commands are forbidden' },
      { pattern: /curl.*\|\s*(ba)?sh/, reason: 'Remote code execution via pipe is forbidden' },
      { pattern: /wget.*\|\s*(ba)?sh/, reason: 'Remote code execution via pipe is forbidden' },
      { pattern: /\bdd\b.*of=\/dev\//, reason: 'Writing to device files is forbidden' },
      { pattern: /\b(mkfs|fdisk)\b/, reason: 'Disk formatting commands are forbidden' },
      { pattern: /\bchmod\s+777\b/, reason: 'chmod 777 is forbidden' },
    ];

    for (const block of hardBlocks) {
      if (block.pattern.test(cmd)) {
        return { allowed: false, reason: block.reason };
      }
    }

    return { allowed: true };
  }
}
