/**
 * BackgroundTaskPool — 后台任务进程池
 *
 * 管理 child_process.spawn 子进程，提供 per-user 和全局并发限制、
 * 超时处理、输出截断，以及 EventEmitter 'task-complete' 事件。
 *
 * PendingResultQueue — 待投递结果队列
 *
 * 保存已完成但尚未投递给 agent 的任务结果，
 * 按 userUuid:sessionId 分组，支持逐条出队。
 */

import { spawn } from 'child_process';
import { EventEmitter } from 'events';
import crypto from 'crypto';

// ─── 配置 ───

const PER_USER_LIMIT   = parseInt(process.env.BG_TASK_PER_USER_LIMIT, 10) || 3;
const GLOBAL_LIMIT     = parseInt(process.env.BG_TASK_GLOBAL_LIMIT, 10)    || 20;
const DEFAULT_TIMEOUT  = parseInt(process.env.BG_TASK_DEFAULT_TIMEOUT, 10) || 600_000;   // 10 min
const MAX_TIMEOUT      = parseInt(process.env.BG_TASK_MAX_TIMEOUT, 10)     || 1_800_000; // 30 min
const MAX_OUTPUT_BYTES = parseInt(process.env.BG_TASK_MAX_OUTPUT, 10)      || 102_400;   // 100 KB

// 已完成任务保留时长（30 min），之后自动清理引用
const COMPLETED_TTL_MS = 30 * 60 * 1000;
// 清理扫描间隔（5 min）
const CLEANUP_INTERVAL_MS = 5 * 60 * 1000;

// ─── BackgroundTaskPool ───

class BackgroundTaskPool extends EventEmitter {
  constructor() {
    super();
    /** @type {Map<string, Task>} 所有任务（running + completed 未清理） */
    this.tasks = new Map();
    /** @type {Map<string, number>} 每用户当前 running 计数 */
    this.userTaskCount = new Map();
    /** 全局 running 计数 */
    this.runningCount = 0;

    // 定期清理已完成任务
    this._cleanupTimer = setInterval(() => this._cleanupCompleted(), CLEANUP_INTERVAL_MS);
    if (this._cleanupTimer.unref) this._cleanupTimer.unref();
  }

  /**
   * 提交一个后台任务
   * @returns {Task} 返回任务对象（status='running'）
   * @throws {Error} 超出并发限制
   */
  submit({ userUuid, sessionId, cwd, command, timeout, label }) {
    // 并发检查
    const userCount = this.userTaskCount.get(userUuid) || 0;
    if (userCount >= PER_USER_LIMIT) {
      throw new Error(`每用户最多同时运行 ${PER_USER_LIMIT} 个后台任务（当前 ${userCount} 个）`);
    }
    if (this.runningCount >= GLOBAL_LIMIT) {
      throw new Error(`系统后台任务已满（最多 ${GLOBAL_LIMIT} 个）`);
    }

    // 规范化 timeout
    const timeoutMs = Math.min(Math.max(timeout || DEFAULT_TIMEOUT, 1000), MAX_TIMEOUT);

    const id = this._genId();
    const task = {
      id,
      userUuid,
      sessionId,
      cwd,
      command,
      label: label || command.slice(0, 80),
      timeout: timeoutMs,
      status: 'running',
      startTime: Date.now(),
      childProcess: null,
      stdout: '',
      stderr: '',
      exitCode: null,
      signal: null,
      truncated: false,
      _stdoutTruncated: false,
      _stderrTruncated: false,
    };

    // 启动子进程
    const child = spawn('sh', ['-c', command], {
      cwd,
      stdio: ['ignore', 'pipe', 'pipe'],
      env: { ...process.env },
    });
    task.childProcess = child;

    // 收集 stdout
    child.stdout.on('data', (chunk) => {
      if (task._stdoutTruncated) return;
      const str = chunk.toString();
      if (task.stdout.length + str.length > MAX_OUTPUT_BYTES) {
        task.stdout += str.slice(0, MAX_OUTPUT_BYTES - task.stdout.length);
        task._stdoutTruncated = true;
        task.truncated = true;
      } else {
        task.stdout += str;
      }
    });

    // 收集 stderr
    child.stderr.on('data', (chunk) => {
      if (task._stderrTruncated) return;
      const str = chunk.toString();
      if (task.stderr.length + str.length > MAX_OUTPUT_BYTES) {
        task.stderr += str.slice(0, MAX_OUTPUT_BYTES - task.stderr.length);
        task._stderrTruncated = true;
        task.truncated = true;
      } else {
        task.stderr += str;
      }
    });

    // 进程结束
    child.on('close', (code, sig) => {
      if (task.status !== 'running') return; // 已被 timeout/cancel 处理
      task.status = 'completed';
      task.exitCode = code;
      task.signal = sig;
      this._onFinished(task);
    });

    child.on('error', (err) => {
      if (task.status !== 'running') return;
      task.status = 'failed';
      task.stderr += `\n[spawn error] ${err.message}`;
      this._onFinished(task);
    });

    // 超时定时器
    task._timeoutTimer = setTimeout(() => {
      if (task.status !== 'running') return;
      task.status = 'timeout';
      // 先 SIGTERM
      try { child.kill('SIGTERM'); } catch (_) { /* ignore */ }
      // 5s 后 SIGKILL
      task._killTimer = setTimeout(() => {
        try { child.kill('SIGKILL'); } catch (_) { /* ignore */ }
      }, 5000);
      this._onFinished(task);
    }, timeoutMs);

    // 注册
    this.tasks.set(id, task);
    this.userTaskCount.set(userUuid, userCount + 1);
    this.runningCount++;

    console.log(`[BgTask] Task ${id} started for user ${userUuid}, session ${sessionId}: ${task.label}`);
    return task;
  }

  /**
   * 取消一个任务
   * @returns {boolean} 是否成功取消
   */
  cancel(taskId, userUuid) {
    const task = this.tasks.get(taskId);
    if (!task) return false;
    if (task.userUuid !== userUuid) return false; // 不允许跨用户取消
    if (task.status !== 'running') return false;

    task.status = 'killed';
    try { task.childProcess.kill('SIGTERM'); } catch (_) { /* ignore */ }
    setTimeout(() => {
      try { task.childProcess.kill('SIGKILL'); } catch (_) { /* ignore */ }
    }, 3000);

    this._onFinished(task);
    return true;
  }

  /** 获取单个任务 */
  getTask(taskId) {
    return this.tasks.get(taskId) || null;
  }

  /** 获取用户所有任务 */
  getUserTasks(userUuid) {
    return [...this.tasks.values()].filter(t => t.userUuid === userUuid);
  }

  /** 获取指定 session 的任务 */
  getSessionTasks(userUuid, sessionId) {
    return [...this.tasks.values()].filter(t => t.userUuid === userUuid && t.sessionId === sessionId);
  }

  /** 统计信息 */
  getStats() {
    return {
      running: this.runningCount,
      total: this.tasks.size,
      perUser: Object.fromEntries(this.userTaskCount),
    };
  }

  // ─── 内部方法 ───

  _onFinished(task) {
    // 清理定时器
    if (task._timeoutTimer) { clearTimeout(task._timeoutTimer); task._timeoutTimer = null; }
    if (task._killTimer) { clearTimeout(task._killTimer); task._killTimer = null; }

    // 更新计数
    const prev = this.userTaskCount.get(task.userUuid) || 1;
    if (prev <= 1) {
      this.userTaskCount.delete(task.userUuid);
    } else {
      this.userTaskCount.set(task.userUuid, prev - 1);
    }
    this.runningCount = Math.max(0, this.runningCount - 1);

    // 释放进程引用
    task.childProcess = null;

    // 记录完成时间
    task.endTime = Date.now();

    console.log(`[BgTask] Task ${task.id} finished: status=${task.status}, exitCode=${task.exitCode}, duration=${task.endTime - task.startTime}ms`);

    // 发出事件
    this.emit('task-complete', task);
  }

  _cleanupCompleted() {
    const now = Date.now();
    for (const [id, task] of this.tasks) {
      if (task.status !== 'running' && task.endTime && now - task.endTime > COMPLETED_TTL_MS) {
        this.tasks.delete(id);
      }
    }
  }

  _genId() {
    return 'bg_' + crypto.randomBytes(6).toString('hex');
  }
}

// ─── PendingResultQueue ───

/** @type {Map<string, object[]>} key = "userUuid:sessionId" */
const pendingResults = new Map();

function _key(userUuid, sessionId) {
  return `${userUuid}:${sessionId}`;
}

/**
 * 将已完成的任务结果加入待投递队列
 */
export function enqueueResult(userUuid, sessionId, taskResult) {
  const k = _key(userUuid, sessionId);
  if (!pendingResults.has(k)) pendingResults.set(k, []);
  pendingResults.get(k).push({
    id: taskResult.id,
    command: taskResult.command,
    label: taskResult.label,
    status: taskResult.status,
    exitCode: taskResult.exitCode,
    signal: taskResult.signal,
    stdout: taskResult.stdout,
    stderr: taskResult.stderr,
    truncated: taskResult.truncated,
    startTime: taskResult.startTime,
    endTime: taskResult.endTime,
    cwd: taskResult.cwd,
    sessionId: taskResult.sessionId,
    userUuid: taskResult.userUuid,
  });
}

/**
 * 从队列取出一条结果（FIFO）
 */
export function dequeueResult(userUuid, sessionId) {
  const k = _key(userUuid, sessionId);
  const q = pendingResults.get(k);
  if (!q || q.length === 0) return null;
  const item = q.shift();
  if (q.length === 0) pendingResults.delete(k);
  return item;
}

/**
 * 检查是否有待投递结果
 */
export function hasResults(userUuid, sessionId) {
  const k = _key(userUuid, sessionId);
  const q = pendingResults.get(k);
  return q && q.length > 0;
}

/**
 * 获取用户所有 session 的待投递结果
 * @returns {Array<{sessionId: string, results: object[]}>}
 */
export function getAllPendingForUser(userUuid) {
  const out = [];
  for (const [k, results] of pendingResults) {
    if (k.startsWith(userUuid + ':')) {
      const sessionId = k.slice(userUuid.length + 1);
      out.push({ sessionId, results: [...results] });
    }
  }
  return out;
}

// ─── 单例导出 ───

export const backgroundTaskPool = new BackgroundTaskPool();
export default backgroundTaskPool;
