/**
 * 进程管理器
 * 负责启动/停止/重启各服务，捕获stdout/stderr并推送到日志系统
 */

import { spawn, execSync } from 'child_process';
import { EventEmitter } from 'events';
import fs from 'fs';
import net from 'net';
import os from 'os';
import path from 'path';
import { fileURLToPath } from 'url';
import { SERVICES, logFile } from './config.js';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const ROOT = path.resolve(__dirname, '../..');
const DB_PORTS = [5432, 5433, 5434];
const DB_COMPOSE_FILE = path.join(ROOT, 'docker-compose.dev.db.yml');
const isWin = os.platform() === 'win32';

// ---- Docker 检测缓存 ----
let _dockerCache = null;
let _dockerCacheTime = 0;
const DOCKER_CACHE_TTL = 5000; // 5秒缓存，避免每次 status 轮询都执行 docker ps

/**
 * 检测哪些服务运行在 Docker 容器中
 * 通过 docker ps 获取所有容器端口映射，与 SERVICES 端口匹配
 * @returns {Map<string, {containerName: string, containerId: string, status: string}>}
 */
// Docker 容器名 → 服务 ID 映射（优先按容器名匹配，避免内部端口无法检测）
const CONTAINER_SVC_MAP = {
  cyrene_ai_core: 'ai-core',
  cyrene_gateway: 'gateway',
  cyrene_memory_service: 'memory-service',
  cyrene_voice_service: 'voice-service',
  cyrene_iot_debug_service: 'iot-debug-service',
  cyrene_plugin_manager: 'plugin-manager',
  cyrene_platform_bridge: 'platform-bridge',
};

function detectDockerServices() {
  const now = Date.now();
  if (_dockerCache && (now - _dockerCacheTime) < DOCKER_CACHE_TTL) {
    return _dockerCache;
  }

  const result = new Map();

  // 容器内模式：无需 docker CLI，直接按容器名映射返回
  if (process.env.RUNNING_IN_DOCKER === 'true') {
    for (const [id] of Object.entries(SERVICES)) {
      if (id === 'frontend') continue;
      const containerName = `cyrene_${id.replace(/-/g, '_')}`;
      result.set(id, { containerName, containerId: '', status: 'Up' });
    }
    _dockerCache = result;
    _dockerCacheTime = now;
    return result;
  }

  // 宿主机模式：通过 docker ps 检测
  try {
    const out = execSync('docker ps --format "{{.ID}}\\t{{.Names}}\\t{{.Ports}}\\t{{.Status}}"', {
      timeout: 5000,
      stdio: 'pipe',
    }).toString().trim();

    if (!out) return result;

    for (const line of out.split('\n')) {
      const [containerId, containerName, ports, status] = line.split('\t');
      const svcId = CONTAINER_SVC_MAP[containerName];
      if (svcId) {
        result.set(svcId, {
          containerName,
          containerId: containerId.substring(0, 12),
          status,
        });
        continue;
      }
      if (!ports) continue;

      const detectedPorts = new Set();
      for (const m of ports.matchAll(/:(\d+)->/g)) {
        detectedPorts.add(parseInt(m[1]));
      }
      for (const [id, svc] of Object.entries(SERVICES)) {
        if (svc.port && detectedPorts.has(svc.port)) {
          result.set(id, {
            containerName,
            containerId: containerId.substring(0, 12),
            status,
          });
        }
      }
    }
  } catch {
    // Docker 不可用，返回空 Map
  }

  _dockerCache = result;
  _dockerCacheTime = now;
  return result;
}

/** 清除 Docker 缓存（用于手动刷新状态） */
export function clearDockerCache() {
  _dockerCache = null;
  _dockerCacheTime = 0;
}

/**
 * 通过 TCP 连接尝试判断端口是否被占用，若被占用则尝试用 fuser 释放
 */
function releasePort(port) {
  return new Promise((resolve) => {
    const sock = new net.Socket();
    sock.setTimeout(1000);
    sock.on('connect', () => {
      sock.destroy();
      // 端口被占用，尝试释放
      try {
        execSync(`fuser -k ${port}/tcp 2>/dev/null || true`, { timeout: 3000 });
      } catch { /* ignore */ }
      setTimeout(resolve, 500);
    });
    sock.on('error', () => {
      sock.destroy();
      resolve(); // 端口空闲
    });
    sock.on('timeout', () => {
      sock.destroy();
      resolve();
    });
    sock.connect(port, '127.0.0.1');
  });
}

/**
 * 检查端口是否可连接 (TCP connect, 超时2秒)
 */
function isPortOpen(port) {
  return new Promise((resolve) => {
    const sock = new net.Socket();
    sock.setTimeout(2000);
    sock.on('connect', () => { sock.destroy(); resolve(true); });
    sock.on('error', () => { sock.destroy(); resolve(false); });
    sock.on('timeout', () => { sock.destroy(); resolve(false); });
    sock.connect(port, '127.0.0.1');
  });
}

/**
 * 确保数据库在线
 * 检查 DB_PORTS 中至少有一个端口可用，若不可用则尝试 docker compose up
 * 等待最多 30 秒检查数据库就绪
 * @param {string} serviceId - 正在启动的服务 ID
 * @param {EventEmitter} emitter - 用于发送日志事件
 */
async function ensureDBOnline(serviceId, emitter) {
  // 1. 快速检查：任意数据库端口是否已在线
  for (const port of DB_PORTS) {
    if (await isPortOpen(port)) {
      emitter.emit('log', serviceId, 'system', `数据库端口 ${port} 已在线`);
      return;
    }
  }

  // 2. 数据库不在线，尝试 docker compose up
  emitter.emit('log', serviceId, 'system', '数据库未启动，正在通过 Docker Compose 启动...');
  try {
    execSync(`docker compose -f "${DB_COMPOSE_FILE}" up -d`, {
      timeout: 60000,
      stdio: 'pipe',
    });
    emitter.emit('log', serviceId, 'system', 'Docker Compose 启动命令已执行，等待数据库就绪...');
  } catch (err) {
    const stderr = err.stderr?.toString() || err.message;
    emitter.emit('log', serviceId, 'error', `Docker Compose 启动失败: ${stderr}`);
  }

  // 3. 等待最多 30 秒检查数据库就绪
  for (let i = 0; i < 30; i++) {
    await new Promise((r) => setTimeout(r, 1000));
    for (const port of DB_PORTS) {
      if (await isPortOpen(port)) {
        emitter.emit('log', serviceId, 'system', `数据库端口 ${port} 已就绪 (等待 ${i + 1}s)`);
        return;
      }
    }
  }

  // 4. 30 秒后仍不可用
  emitter.emit('log', serviceId, 'error', '⚠️ 数据库无法启动，请手动检查 Docker。将继续启动后端服务...');
}

// ── Watchdog 配置 ──
// 自动重启策略：进程异常退出时自动重启，指数退避，超过上限后停止
const WATCHDOG = {
  MAX_RETRIES: 5,            // 滑动窗口内最大重试次数
  RETRY_WINDOW_MS: 5 * 60 * 1000,  // 重试计数滑动窗口 (5 分钟)
  BASE_DELAY_MS: 1000,       // 首次重试延迟
  MAX_DELAY_MS: 60 * 1000,   // 最大重试延迟 (指数退避上限)
  STABLE_RESET_MS: 2 * 60 * 1000,  // 稳定运行此时间后重置重试计数

  // 可以为每个服务单独覆盖配置，按 serviceId 索引
  OVERRIDES: {},
};

class ProcessManager extends EventEmitter {
  constructor() {
    super();
    /** @type {Map<string, {process: ChildProcess|null, status: string, startTime: number|null, pid: number|null, buildLog: string[], retryCount: number, retryHistory: number[], stableTimer: NodeJS.Timeout|null}>} */
    this.processes = new Map();

    for (const id of Object.keys(SERVICES)) {
      this.processes.set(id, {
        process: null,
        status: 'stopped',
        startTime: null,
        pid: null,
        buildLog: [],
        retryCount: 0,
        retryHistory: [],     // crash timestamps in current window
        stableTimer: null,
      });
    }
  }

  /**
   * 获取服务的 watchdog 配置（合并默认值和覆盖）
   */
  _watchdogConfig(serviceId) {
    const defaults = {
      maxRetries: WATCHDOG.MAX_RETRIES,
      retryWindowMs: WATCHDOG.RETRY_WINDOW_MS,
      baseDelayMs: WATCHDOG.BASE_DELAY_MS,
      maxDelayMs: WATCHDOG.MAX_DELAY_MS,
      stableResetMs: WATCHDOG.STABLE_RESET_MS,
    };
    const overrides = WATCHDOG.OVERRIDES[serviceId] || {};
    return { ...defaults, ...overrides };
  }

  /**
   * 清理滑动窗口外的旧崩溃记录
   */
  _pruneRetryHistory(procInfo, windowMs) {
    const cutoff = Date.now() - windowMs;
    procInfo.retryHistory = procInfo.retryHistory.filter(ts => ts > cutoff);
    procInfo.retryCount = procInfo.retryHistory.length;
  }

  /**
   * 启动稳定运行计时器：服务稳定运行一段时间后重置重试计数
   */
  _startStableTimer(serviceId, procInfo) {
    const cfg = this._watchdogConfig(serviceId);
    if (procInfo.stableTimer) clearTimeout(procInfo.stableTimer);
    procInfo.stableTimer = setTimeout(() => {
      if (procInfo.retryCount > 0) {
        this.emit('log', serviceId, 'system',
          `✅ Watchdog: 服务已稳定运行 ${Math.round(cfg.stableResetMs / 1000)}s，重置崩溃计数 (之前 ${procInfo.retryCount} 次)`);
      }
      procInfo.retryCount = 0;
      procInfo.retryHistory = [];
      procInfo.stableTimer = null;
    }, cfg.stableResetMs);
  }

  /**
   * 启动服务
   */
  async start(serviceId) {
    const svc = SERVICES[serviceId];
    if (!svc) throw new Error(`未知服务: ${serviceId}`);

    // Docker 管理的服务拒绝本地操作
    if (detectDockerServices().has(serviceId)) {
      return { success: false, error: 'docker_managed', message: `${svc.name} 由 Docker 管理，请使用 docker compose 控制` };
    }

    const procInfo = this.processes.get(serviceId);
    if (procInfo.process) {
      throw new Error(`${svc.name} 已在运行中`);
    }

    // 如果服务已在运行（例如手动启动），通过健康检查自动接管，避免杀进程
    if (svc.healthUrl) {
      try {
        const resp = await fetch(svc.healthUrl, { signal: AbortSignal.timeout(3000) });
        if (resp.ok) {
          let pid = null;
          try {
            if (isWin) {
              // Windows: use netstat -ano to find PID by port
              const out = execSync(`netstat -ano | findstr ":${svc.port} " | findstr "LISTENING"`, { timeout: 3000, stdio: 'pipe' }).toString().trim();
              const lines = out.split('\n');
              for (const line of lines) {
                const parts = line.trim().split(/\s+/);
                const last = parts[parts.length - 1];
                if (/^\d+$/.test(last)) { pid = parseInt(last); break; }
              }
            } else {
              const out = execSync(`fuser ${svc.port}/tcp 2>/dev/null || true`, { timeout: 2000 }).toString().trim();
              const match = out.match(/(\d+)/);
              if (match) pid = parseInt(match[1]);
            }
          } catch { /* ignore */ }
          procInfo.pid = pid;
          procInfo.startTime = Date.now();
          procInfo.status = 'running';
          procInfo.process = null;
          this.emit('log', serviceId, 'system', `${svc.name} 已在运行 (PID: ${pid || '未知'})，已接管（无需重启）`);
          this._startStableTimer(serviceId, procInfo);
          return { success: true, message: `${svc.name} 已接管 (无需重启)` };
        }
      } catch { /* 不可达，继续启动新进程 */ }
    }

    // 对需要数据库的服务做前置检查
    if (['gateway', 'ai-core', 'memory-service', 'plugin-manager', 'platform-bridge'].includes(serviceId)) {
      this.emit('log', serviceId, 'system', '检查数据库连接状态...');
      await ensureDBOnline(serviceId, this);
    }

    // 启动前释放端口，避免 "address already in use"
    if (svc.port) {
      this.emit('log', serviceId, 'system', `检查端口 ${svc.port}...`);
      await releasePort(svc.port);
    }

    this.emit('log', serviceId, 'system', `正在启动 ${svc.name}...`);
    procInfo.status = 'starting';
    procInfo.buildLog = [];

    // 确保日志目录存在
    const logPath = logFile(serviceId);
    const logDir = path.dirname(logPath);
    fs.mkdirSync(logDir, { recursive: true });

    const logStream = fs.createWriteStream(logPath, { flags: 'a' });

    // 确定二进制路径或命令
    let command, args;
    if (svc.command === './main') {
      command = isWin ? './main.exe' : './main';
      args = svc.args || [];
    } else if (svc.command === 'npx') {
      command = isWin ? 'npx.cmd' : (svc.npmBin || 'npx');
      args = svc.args || [];
    } else {
      command = svc.command;
      args = svc.args || [];
    }

    // 对使用 npm 的服务，检查 node_modules 是否完整
    if (svc.command === 'npx' || svc.command === 'node') {
      const modulesDir = path.join(svc.cwd, 'node_modules');
      const installMarker = path.join(modulesDir, '.package-lock.json');
      if (!fs.existsSync(installMarker)) {
        // 如果 node_modules 目录存在但不完整，先删除
        if (fs.existsSync(modulesDir)) {
          this.emit('log', serviceId, 'system', 'node_modules 不完整，正在清理...');
          fs.rmSync(modulesDir, { recursive: true, force: true });
        }
        this.emit('log', serviceId, 'system', '正在运行 npm install...');
        // Windows: npm.cmd batch file has module resolution issues when
        // cwd has a node_modules directory, even if empty. Use node+npm-cli.js directly.
        const installCmd = isWin
          ? `"${process.execPath}" "${path.join(path.dirname(process.execPath), 'node_modules/npm/bin/npm-cli.js')}" install`
          : 'npm install';
        try {
          execSync(installCmd, { cwd: svc.cwd, timeout: 120000, stdio: 'pipe' });
          this.emit('log', serviceId, 'system', 'npm install 完成');
        } catch (err) {
          const stderr = err.stderr?.toString() || err.message;
          this.emit('log', serviceId, 'error', `npm install 失败: ${stderr}`);
          throw new Error(`npm install 失败: ${stderr}`);
        }
      }
    }

    const env = { ...process.env, ...svc.env };
    // .cmd/.bat on Windows needs shell:true
    const needsShell = isWin && (command.endsWith('.cmd') || command.endsWith('.bat'));

    // Go 后端进程使用 detached 确保 ethend 崩溃后独立存活
    // npx/node 进程不使用 detached 避免 Windows 弹窗
    const isGoSvc = svc.command === './main';
    const child = spawn(command, args, {
      cwd: svc.cwd,
      env,
      stdio: ['ignore', 'pipe', 'pipe'],
      shell: needsShell,
      windowsHide: true,
      detached: isGoSvc,
    });
    if (isGoSvc) {
      child.unref(); // 解除父子关系，ethen 退出不影响子进程
    }

    child.stdout.on('data', (data) => {
      const text = data.toString();
      logStream.write(text);
      this.emit('log', serviceId, 'stdout', text);
    });

    child.stderr.on('data', (data) => {
      const text = data.toString();
      logStream.write(text);
      this.emit('log', serviceId, 'stderr', text);
    });

    // spawn() 返回后进程已启动，立即记录 PID 和状态
    // 注意: Node.js 没有 'spawn' 事件，spawn() 调用本身是同步的
    procInfo.pid = child.pid;
    procInfo.startTime = Date.now();
    procInfo.status = 'running';
    procInfo.process = child;
    this.emit('log', serviceId, 'system', `${svc.name} 已启动 (PID: ${child.pid})`);

    child.on('error', (err) => {
      const msg = `进程错误: ${err.message}`;
      logStream.write(msg + '\n');
      this.emit('log', serviceId, 'error', msg);
      procInfo.status = 'error';
      procInfo.process = null;
      procInfo.pid = null;
    });

    child.on('close', (code) => {
      const exitMsg = `进程退出，退出码: ${code}`;
      logStream.write(exitMsg + '\n');
      this.emit('log', serviceId, 'system', exitMsg);
      procInfo.status = 'stopped';
      procInfo.process = null;
      procInfo.pid = null;
      logStream.end();

      // 清除稳定运行计时器
      if (procInfo.stableTimer) {
        clearTimeout(procInfo.stableTimer);
        procInfo.stableTimer = null;
      }

      // ── Watchdog 自动重启判断 ──
      const isNormalExit = code === 0 || code === null; // null = signal kill (e.g. SIGTERM from manual stop)
      // 检查是否是用户手动停止 (通过 _manualStop 标记)
      const wasManualStop = procInfo._manualStop === true;
      procInfo._manualStop = false; // 重置标记

      if (isNormalExit || wasManualStop) {
        // 正常退出或手动停止：不触发 watchdog
        procInfo.retryCount = 0;
        procInfo.retryHistory = [];
        return;
      }

      // 异常退出 (code !== 0)：尝试自动重启
      const wdCfg = this._watchdogConfig(serviceId);
      this._pruneRetryHistory(procInfo, wdCfg.retryWindowMs);
      procInfo.retryHistory.push(Date.now());
      procInfo.retryCount = procInfo.retryHistory.length;

      if (procInfo.retryCount > wdCfg.maxRetries) {
        const windowSec = Math.round(wdCfg.retryWindowMs / 1000);
        this.emit('log', serviceId, 'error',
          `🚨 Watchdog: ${svc.name} 在 ${windowSec}s 内崩溃 ${procInfo.retryCount} 次，已达上限 (${wdCfg.maxRetries})，停止自动重启。请手动排查问题后重启。`);
        procInfo.status = 'crashed';
        return;
      }

      // 计算指数退避延迟
      const delay = Math.min(
        wdCfg.baseDelayMs * Math.pow(2, procInfo.retryCount - 1),
        wdCfg.maxDelayMs
      );
      const delaySec = Math.round(delay / 1000);
      this.emit('log', serviceId, 'system',
        `🔄 Watchdog: ${svc.name} 异常退出 (第 ${procInfo.retryCount}/${wdCfg.maxRetries} 次)，${delaySec}s 后自动重启...`);

      setTimeout(async () => {
        try {
          this.emit('log', serviceId, 'system', `🔄 Watchdog: 正在自动重启 ${svc.name}...`);
          const result = await this.start(serviceId);
          if (result.success) {
            this.emit('log', serviceId, 'system', `✅ Watchdog: ${svc.name} 自动重启成功`);
          } else {
            this.emit('log', serviceId, 'error', `❌ Watchdog: ${svc.name} 自动重启失败: ${result.message}`);
          }
        } catch (err) {
          this.emit('log', serviceId, 'error', `❌ Watchdog: ${svc.name} 自动重启异常: ${err.message}`);
        }
      }, delay);
    });

    // 启动稳定运行计时器
    this._startStableTimer(serviceId, procInfo);

    return { success: true, message: `${svc.name} 启动中...` };
  }

  /**
   * 停止服务
   */
  async stop(serviceId) {
    const svc = SERVICES[serviceId];
    if (!svc) throw new Error(`未知服务: ${serviceId}`);

    if (detectDockerServices().has(serviceId)) {
      return { success: false, error: 'docker_managed', message: `${svc.name} 由 Docker 管理，请使用 docker compose 控制` };
    }

    const procInfo = this.processes.get(serviceId);
    if (!procInfo.process) {
      // 接管模式（未持有进程句柄）：通过端口反查 PID 并强制杀死
      if (svc.port && procInfo.pid) {
        try {
          if (isWin) {
            execSync(`taskkill /F /PID ${procInfo.pid}`, { timeout: 5000, stdio: 'pipe' });
          } else {
            execSync(`kill -9 ${procInfo.pid}`, { timeout: 5000, stdio: 'pipe' });
          }
          this.emit('log', serviceId, 'system', `${svc.name} 已通过 PID 强制停止 (PID: ${procInfo.pid})`);
        } catch (e) {
          this.emit('log', serviceId, 'system', `${svc.name} PID ${procInfo.pid} 已不存在或无法杀死`);
        }
      } else if (svc.port) {
        // 没有 PID 但有端口：用 fuser 释放端口
        try {
          execSync(`fuser -k ${svc.port}/tcp 2>/dev/null || true`, { timeout: 5000, stdio: 'pipe' });
          this.emit('log', serviceId, 'system', `${svc.name} 端口 ${svc.port} 已释放`);
        } catch { /* fuser not available */ }
      }
      procInfo.status = 'stopped';
      procInfo.pid = null;
      procInfo.startTime = null;
      // 等待 1 秒确保端口释放
      await new Promise(r => setTimeout(r, 1000));
      return { success: true, message: `${svc.name} 已停止` };
    }

    // 标记为手动停止，防止 watchdog 自动重启
    procInfo._manualStop = true;

    return new Promise((resolve) => {
      const timeout = setTimeout(() => {
        // 强制杀死
        if (procInfo.process) {
          procInfo.process.kill('SIGKILL');
        }
        procInfo.status = 'stopped';
        procInfo.process = null;
        procInfo.pid = null;
        resolve({ success: true, message: `${svc.name} 已强制停止` });
      }, 5000);

      procInfo.process.on('close', () => {
        clearTimeout(timeout);
        procInfo.status = 'stopped';
        procInfo.process = null;
        procInfo.pid = null;
        resolve({ success: true, message: `${svc.name} 已停止` });
      });

      procInfo.process.kill('SIGTERM');
      this.emit('log', serviceId, 'system', `正在停止 ${svc.name}...`);
    });
  }

  /**
   * 重启服务
   */
  async restart(serviceId) {
    if (detectDockerServices().has(serviceId)) {
      const svc = SERVICES[serviceId];
      return { success: false, error: 'docker_managed', message: `${svc?.name || serviceId} 由 Docker 管理` };
    }
    await this.stop(serviceId);
    await new Promise((r) => setTimeout(r, 1000));
    return this.start(serviceId);
  }

  /**
   * 构建服务 (Go服务需要预编译)
   */
  async build(serviceId) {
    const svc = SERVICES[serviceId];
    if (!svc) throw new Error(`未知服务: ${serviceId}`);

    if (detectDockerServices().has(serviceId)) {
      return { success: false, error: 'docker_managed', message: `${svc.name} 由 Docker 管理，请在容器内构建或重建镜像` };
    }

    if (!svc.buildCommand) {
      return { success: false, message: `${svc.name} 不需要预编译` };
    }

    const procInfo = this.processes.get(serviceId);
    procInfo.status = 'building';
    procInfo.buildLog = [];
    this.emit('log', serviceId, 'system', `正在编译 ${svc.name}...`);

    return new Promise((resolve) => {
      const buildCmd = svc.goBin || svc.buildCommand;
      const buildArgs = svc.buildArgs || [];

      const child = spawn(buildCmd, buildArgs, {
        cwd: svc.cwd,
        env: { ...process.env, GOPROXY: 'https://goproxy.cn,direct', GOWORK: 'off' },
        stdio: ['ignore', 'pipe', 'pipe'],
        windowsHide: true,
      });

      let stdout = '';
      let stderr = '';

      child.stdout.on('data', (d) => { stdout += d.toString(); });
      child.stderr.on('data', (d) => { stderr += d.toString(); });

      child.on('close', (code) => {
        procInfo.status = 'stopped';
        procInfo.buildLog = [
          ...stdout.split('\n').filter(Boolean),
          ...stderr.split('\n').filter(Boolean),
        ];

        if (code === 0) {
          this.emit('log', serviceId, 'system', `${svc.name} 编译成功`);
          resolve({ success: true, message: `${svc.name} 编译成功` });
        } else {
          this.emit('log', serviceId, 'error', `${svc.name} 编译失败:\n${stderr || stdout}`);
          resolve({ success: false, message: '编译失败', buildLog: procInfo.buildLog });
        }
      });

      child.on('error', (err) => {
        procInfo.status = 'stopped';
        resolve({ success: false, message: `编译错误: ${err.message}` });
      });
    });
  }

  /**
   * 获取所有服务状态
   */
  getStatus() {
    const dockerSvcs = detectDockerServices();
    const result = {};
    for (const [id, info] of this.processes) {
      const svc = SERVICES[id];
      const docker = dockerSvcs.get(id);
      let source = 'none';
      if (docker) {
        source = 'docker';
      } else if (info.status === 'running' || info.status === 'starting') {
        source = 'local';
      }
      result[id] = {
        name: svc.name,
        status: docker ? 'running' : info.status, // Docker 容器总是 running
        pid: docker ? null : info.pid,
        startTime: info.startTime,
        uptime: info.startTime ? Date.now() - info.startTime : 0,
        port: svc.port,
        healthUrl: svc.healthUrl,
        source,
        retryCount: info.retryCount || 0,
        ...(docker ? { containerName: docker.containerName, containerId: docker.containerId } : {}),
      };
    }
    return result;
  }

  /**
   * 获取单个服务状态
   */
  getServiceStatus(serviceId) {
    const info = this.processes.get(serviceId);
    if (!info) return null;
    const svc = SERVICES[serviceId];
    const dockerSvcs = detectDockerServices();
    const docker = dockerSvcs.get(serviceId);
    let source = 'none';
    if (docker) {
      source = 'docker';
    } else if (info.status === 'running' || info.status === 'starting') {
      source = 'local';
    }
    return {
      name: svc.name,
      status: docker ? 'running' : info.status,
      pid: docker ? null : info.pid,
      startTime: info.startTime,
      uptime: info.startTime ? Date.now() - info.startTime : 0,
      port: svc.port,
      healthUrl: svc.healthUrl,
      source,
      retryCount: info.retryCount || 0,
      ...(docker ? { containerName: docker.containerName, containerId: docker.containerId } : {}),
    };
  }

  /**
   * 停止所有服务
   */
  async stopAll() {
    const results = [];
    const dockerSvcs = detectDockerServices();
    for (const id of Object.keys(SERVICES)) {
      if (dockerSvcs.has(id)) {
        const svc = SERVICES[id];
        results.push({ id, success: true, message: `${svc.name} 由 Docker 管理，跳过停止`, docker: true });
        continue;
      }
      try {
        const r = await this.stop(id);
        results.push({ id, ...r });
      } catch (err) {
        results.push({ id, success: false, message: err.message });
      }
    }
    return results;
  }

  /**
   * 尝试接管已运行的服务 (通过健康检查端点)
   * 如果服务已在运行，直接标记为 running 而不是杀死重启
   */
  async tryAdopt(serviceId) {
    const svc = SERVICES[serviceId];
    if (!svc || !svc.healthUrl) return false;

    try {
      const resp = await fetch(svc.healthUrl, { signal: AbortSignal.timeout(3000) });
      if (resp.ok) {
        const procInfo = this.processes.get(serviceId);
        // 通过端口反查 PID
        let pid = null;
        try {
          if (isWin) {
            const out = execSync(`netstat -ano | findstr ":${svc.port} " | findstr "LISTENING"`, { timeout: 3000, stdio: 'pipe' }).toString().trim();
            const lines = out.split('\n');
            for (const line of lines) {
              const parts = line.trim().split(/\s+/);
              const last = parts[parts.length - 1];
              if (/^\d+$/.test(last)) { pid = parseInt(last); break; }
            }
          } else {
            const out = execSync(`fuser ${svc.port}/tcp 2>/dev/null || true`, { timeout: 2000 }).toString().trim();
            const match = out.match(/(\d+)/);
            if (match) pid = parseInt(match[1]);
          }
        } catch { /* ignore */ }

        procInfo.pid = pid;
        procInfo.startTime = Date.now();
        procInfo.status = 'running';
        procInfo.process = null; // 不是我们的子进程，但标记为已接管
        this.emit('log', serviceId, 'system', `${svc.name} 已在运行 (PID: ${pid || '未知'})，已接管`);
        return true;
      }
    } catch { /* 未运行或不可达 */ }
    return false;
  }

  /**
   * 检查服务是否需要编译 (Go 服务且二进制不存在)
   */
  needsBuild(serviceId) {
    const svc = SERVICES[serviceId];
    if (!svc || !svc.buildCommand) return false;

    const binaryPath = path.join(svc.cwd, 'main');
    const exePath = binaryPath + '.exe';
    return !fs.existsSync(binaryPath) && !fs.existsSync(exePath);
  }

  /**
   * 按顺序启动所有服务 (memory → iot → voice → ai-core → gateway → frontend)
   * 每步等待健康检查通过后再启动下一个
   */
  async startAllSequential() {
  	const order = ['memory-service', 'plugin-manager', 'iot-debug-service', 'voice-service', 'ai-core', 'platform-bridge', 'gateway', 'frontend'];
  	const results = [];
  	const dockerSvcs = detectDockerServices();

  	for (const id of order) {
  		const svc = SERVICES[id];

  		// Docker 管理的服务：跳过
  		if (dockerSvcs.has(id)) {
  			const d = dockerSvcs.get(id);
  			this.emit('log', id, 'system', `${svc.name} 由 Docker 容器 ${d.containerName} 管理，跳过本地启动`);
  			results.push({ id, success: true, message: `${svc.name} 由 Docker 管理 (${d.containerName})，已跳过`, docker: true });
  			continue;
  		}

  		// 先尝试接管已运行的服务
  		const adopted = await this.tryAdopt(id);
  		if (adopted) {
  			results.push({ id, success: true, message: `${svc.name} 已接管 (无需重启)` });
  			continue;
  		}

  		// 编译检查: 如果 Go 服务二进制不存在，先编译
  		if (this.needsBuild(id)) {
  			this.emit('log', id, 'system', `未找到编译产物，正在编译 ${svc.name}...`);
  			const buildResult = await this.build(id);
  			if (!buildResult.success) {
  				const errMsg = `编译失败: ${buildResult.message}`;
  				this.emit('log', id, 'error', errMsg);
  				results.push({ id, success: false, message: errMsg });
  				continue;
  			}
  			this.emit('log', id, 'system', `${svc.name} 编译完成`);
  		}

  		// 启动服务
  		try {
  			const r = await this.start(id);
  			results.push({ id, ...r });

  			// 等待健康检查通过
  			if (svc.healthUrl) {
  				let healthy = false;
  				for (let i = 0; i < 15; i++) {
  					await new Promise((r) => setTimeout(r, 1000));
  					try {
  						const resp = await fetch(svc.healthUrl, { signal: AbortSignal.timeout(2000) });
  						if (resp.ok) { healthy = true; break; }
  					} catch { /* continue waiting */ }
  				}
  				if (!healthy) {
  					this.emit('log', id, 'error', `${svc.name} 健康检查超时`);
  				} else {
  					this.emit('log', id, 'system', `${svc.name} 健康检查通过 ✓`);
  					// Gateway 和 AI-Core 启动后额外等待 2 秒，确保内部路由和 Handler 完全初始化
  					if (id === 'gateway' || id === 'ai-core') {
  						await new Promise((r) => setTimeout(r, 2000));
  						this.emit('log', id, 'system', `${svc.name} 已就绪 (额外等待 2s 确保服务稳定)`);
  					}
  				}
  			}
  		} catch (err) {
  			results.push({ id, success: false, message: err.message });
  		}
  	}

  	return results;
  }
}

export const processManager = new ProcessManager();
