'use strict';

const { exec, spawn } = require('child_process');
const path = require('path');
const { getContainerContext, resolveContainerPath, buildEnvArgs } = require('./container_bridge');

function resolvePath(workspace, p) {
  if (!p) return workspace;
  if (path.isAbsolute(p)) return p;
  return path.join(workspace, p);
}

function runCommandTool(workspace, args, abortSignal) {
  return new Promise((resolve) => {
    const cmd = args.command;
    const timeoutSec = Number(args.timeout || 0);
    const cwd = resolvePath(workspace, args.working_dir || '.');
    const ctx = getContainerContext();
    if (!cmd) return resolve({ success: false, error: 'command 不能为空' });
    if (abortSignal && abortSignal.aborted) {
      return resolve({ success: false, error: '任务被用户取消', cancelled: true });
    }
    const timeoutMs = Math.max(0, timeoutSec) * 1000;
    let finished = false;

    if (ctx) {
      const resolved = resolveContainerPath(workspace, args.working_dir || '.', ctx);
      if (resolved.error) {
        return resolve({ success: false, error: resolved.error });
      }
      const workdir = resolved.containerPath || ctx.mountPath;
      const execArgs = [ 'exec', '-i' ];
      if (workdir) execArgs.push('-w', workdir);
      execArgs.push(...buildEnvArgs(ctx));
      const venv = ctx.containerVenv || '/opt/agent-venv';
      const basePath = '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin';
      const exportPrefix = `export VIRTUAL_ENV=${venv}; export PATH=${venv}/bin:${basePath}; `;
      const wrappedCmd = `${exportPrefix}${cmd}`;
      execArgs.push(ctx.containerName, 'sh', '-c', wrappedCmd);
      const child = spawn(ctx.dockerBin, execArgs, { stdio: ['ignore', 'pipe', 'pipe'] });
      let stdout = '';
      let stderr = '';
      const onData = (chunk, buffer) => buffer.push(chunk);
      const stdoutBuf = [];
      const stderrBuf = [];
      child.stdout.on('data', (chunk) => onData(chunk, stdoutBuf));
      child.stderr.on('data', (chunk) => onData(chunk, stderrBuf));
      const done = (result) => {
        if (finished) return;
        finished = true;
        if (abortSignal) abortSignal.removeEventListener('abort', onAbort);
        return resolve(result);
      };
      const onAbort = () => {
        if (finished) return;
        finished = true;
        try {
          child.kill('SIGTERM');
        } catch (_) {}
        return resolve({ success: false, error: '任务被用户取消', cancelled: true });
      };
      if (abortSignal) abortSignal.addEventListener('abort', onAbort, { once: true });
      let timer = null;
      if (timeoutMs) {
        timer = setTimeout(() => {
          try {
            child.kill('SIGTERM');
          } catch (_) {}
          const output = Buffer.concat(stdoutBuf).toString() + Buffer.concat(stderrBuf).toString();
          done({
            success: false,
            status: 'timeout',
            error: '命令超时',
            return_code: null,
            output,
            timeout: timeoutSec,
          });
        }, timeoutMs);
      }
      child.on('close', (code) => {
        if (timer) clearTimeout(timer);
        const output = Buffer.concat(stdoutBuf).toString() + Buffer.concat(stderrBuf).toString();
        if (finished) return;
        if (code && code !== 0) {
          return done({
            success: false,
            status: 'error',
            error: `exit ${code}`,
            return_code: code,
            output,
          });
        }
        return done({ success: true, status: 'ok', output });
      });
      return;
    }

    const child = exec(cmd, { cwd, timeout: timeoutMs, maxBuffer: 10 * 1024 * 1024, shell: true }, (err, stdout, stderr) => {
      if (finished) return;
      finished = true;
      if (abortSignal) abortSignal.removeEventListener('abort', onAbort);
      const output = [stdout, stderr].filter(Boolean).join('');
      if (err) {
        const isTimeout = err.killed && err.signal === 'SIGTERM';
        return resolve({
          success: false,
          status: isTimeout ? 'timeout' : 'error',
          error: err.message,
          return_code: err.code,
          output,
          timeout: timeoutSec,
        });
      }
      resolve({ success: true, status: 'ok', output });
    });
    const onAbort = () => {
      if (finished) return;
      finished = true;
      try {
        child.kill('SIGTERM');
      } catch (_) {}
      return resolve({ success: false, error: '任务被用户取消', cancelled: true });
    };
    if (abortSignal) abortSignal.addEventListener('abort', onAbort, { once: true });
  });
}

module.exports = { runCommandTool };
