/**
 * `ccl setup codex` — 使用 Codex 原生 `codex mcp add` 安装 ClawClaw MCP server
 *
 *   优先:   codex mcp add clawclaw --env CLAWCLAW_WS_URL=... -- <启动命令>
 *   回退:   直接写 ~/.codex/config.toml(codex 不可用时)
 *
 * 自动设置 CLAWCLAW_WS_URL,实现 clawclaw_game_start 零参数调用。
 *
 * 用法:
 *   ccl setup codex                # dry-run 预览
 *   ccl setup codex -y             # 应用(默认 ws://127.0.0.1:19997)
 *   ccl setup codex -y --ws-port 19998  # 指定端口
 *   ccl setup codex --print        # 仅输出等价命令行
 */

import { Command } from 'commander';
import { homedir } from 'os';
import { join } from 'path';
import { existsSync, readFileSync, appendFileSync, copyFileSync, readdirSync, statSync as fsStatSync } from 'fs';
import { spawnSync } from 'child_process';

// ─── 路径解析 ──────────────────────────────────────────────────

function resolveCodexConfigPath(): string {
  const home = process.env.CODEX_HOME?.trim();
  if (home) return join(home, 'config.toml');
  return join(homedir(), '.codex', 'config.toml');
}

function resolveCodexClawclawEntry(): { command: string; args: string[] } | null {
  const isWin = process.platform === 'win32';
  const appData = process.env.APPDATA || join(homedir(), 'AppData', 'Roaming');

  // 1. dist/mcp-server.js 优先(编译后的纯 JS,无 tsx stdout 污染,最可靠)
  const distCandidates = [
    join(appData, 'npm', 'node_modules', 'codex-clawclaw', 'dist', 'mcp-server.js'),
    join('D:', 'codex-clawclaw', 'dist', 'mcp-server.js'),
  ];
  for (const dist of distCandidates) {
    try { if (existsSync(dist)) return { command: 'node', args: [dist] }; } catch { /* continue */ }
  }

  // 2. .mjs 包装器(bin/codex-clawclaw.mjs, 自注册 tsx, 直接 node 运行)
  const mjsCandidates = [
    join(appData, 'npm', 'node_modules', 'codex-clawclaw', 'bin', 'codex-clawclaw.mjs'),
    join('D:', 'codex-clawclaw', 'bin', 'codex-clawclaw.mjs'),
  ];
  for (const mjs of mjsCandidates) {
    try { if (existsSync(mjs)) return { command: process.execPath, args: [mjs] }; } catch { /* continue */ }
  }

  // 3. PATH 上找 bin(.cmd)
  const cmdNames = isWin
    ? ['codex-clawclaw.cmd', 'codex-clawclaw.ps1', 'codex-clawclaw']
    : ['codex-clawclaw'];
  const sep = isWin ? '\\' : '/';
  const pathDirs = (process.env.PATH || '').split(isWin ? ';' : ':').filter(Boolean);
  for (const dir of pathDirs) {
    for (const name of cmdNames) {
      const full = `${dir}${sep}${name}`;
      try { if (existsSync(full)) return { command: full, args: [] }; } catch { /* continue */ }
    }
  }

  // 4. 旧版路径(src/mcp-server.ts, 需搭配 tsx)
  const tsCandidates = [
    join(appData, 'npm', 'node_modules', 'codex-clawclaw', 'src', 'mcp-server.ts'),
    join('D:', 'codex-clawclaw', 'src', 'mcp-server.ts'),
  ];
  for (const ts of tsCandidates) {
    try { if (existsSync(ts)) return { command: process.execPath, args: [resolveTsxCli(), ts] }; } catch { /* continue */ }
  }

  return null;
}

function resolveTsxCli(): string {
  const appData = process.env.APPDATA || join(homedir(), 'AppData', 'Roaming');
  const candidates = [
    join(appData, 'npm', 'node_modules', 'tsx', 'dist', 'cli.mjs'),
    join('D:', 'codex-clawclaw', 'node_modules', 'tsx', 'dist', 'cli.mjs'),
  ];
  for (const c of candidates) {
    try { if (existsSync(c)) return c; } catch { /* continue */ }
  }
  return 'tsx';
}

/** 解析 codex CLI 的可执行文件路径(直接 .exe,不依赖 shell shim) */
function resolveCodexExe(): string | null {
  // 1. 从 config.toml 读取 CODEX_CLI_PATH(ccl 自己的全局配置)
  const configPath = join(homedir(), '.clawclaw', 'config.json');
  try {
    if (existsSync(configPath)) {
      const cfg = JSON.parse(readFileSync(configPath, 'utf-8'));
      if (cfg.codexCliPath && existsSync(cfg.codexCliPath)) return cfg.codexCliPath;
    }
  } catch { /* ignore */ }

  // 2. 从 ~/.codex/config.toml 读取 CODEX_CLI_PATH 环境变量
  //    搜索 AppData\Local\OpenAI\Codex\bin\ 下最新的 codex.exe
  const appData = process.env.LOCALAPPDATA || join(homedir(), 'AppData', 'Local');
  const codexBinDir = join(appData, 'OpenAI', 'Codex', 'bin');
  try {
    if (existsSync(codexBinDir)) {
      const dirs = readdirSync(codexBinDir).filter((d: string) => {
        try { return fsStatSync(join(codexBinDir, d)).isDirectory(); } catch { return false; }
      }).sort().reverse(); // 最新版本优先
      for (const d of dirs) {
        const exe = join(codexBinDir, d, 'codex.exe');
        try { if (existsSync(exe)) return exe; } catch { /* continue */ }
      }
    }
  } catch { /* ignore */ }

  // 3. PATH 上找 codex.cmd(Windows)
  const pathDirs = (process.env.PATH || '').split(';').filter(Boolean);
  for (const dir of pathDirs) {
    const full = join(dir, 'codex.cmd');
    try { if (existsSync(full)) return full; } catch { /* continue */ }
  }

  return null;
}

function codexMcpAvailable(): boolean {
  const exe = resolveCodexExe();
  if (!exe) return false;
  try {
    const r = spawnSync(exe, ['mcp', 'list', '--json'], {
      env: { ...process.env, NO_COLOR: '1' },
      windowsHide: true, timeout: 10_000, encoding: 'utf-8',
    });
    return r.status === 0;
  } catch { return false; }
}

function codexMcpAlreadyRegistered(): boolean {
  const exe = resolveCodexExe();
  if (!exe) return false;
  try {
    const r = spawnSync(exe, ['mcp', 'list', '--json'], {
      env: { ...process.env, NO_COLOR: '1' },
      windowsHide: true, timeout: 10_000, encoding: 'utf-8',
    });
    if (r.status !== 0 || !r.stdout) return false;
    const servers = JSON.parse(r.stdout);
    return Array.isArray(servers) && servers.some((s: any) => s.name === 'clawclaw');
  } catch { return false; }
}

// ─── Commander ─────────────────────────────────────────────────

export function createSetupCodexSubcommand(): Command {
  return new Command('codex')
    .description('使用 codex mcp add 安装 ClawClaw MCP server(自动配置 CLAWCLAW_WS_URL,实现零参数启动游戏)。')
    .option('-y, --yes', '应用更改(默认 dry-run)')
    .option('--print', '仅输出推荐命令')
    .option('--ws-port <port>', 'app-server WebSocket 端口(默认 19997)', '19997')
    .action((opts: { yes?: boolean; print?: boolean; wsPort?: string }) => {
      const wsPort = opts.wsPort || '19997';
      const wsUrl = `ws://127.0.0.1:${wsPort}`;
      const entry = resolveCodexClawclawEntry();
      if (!entry) {
        console.log('未找到 codex-clawclaw。');
        console.log('安装: npm install -g @myclaw163/codex-clawclaw --registry https://registry.npmmirror.com/');
        console.log('本地开发: 在 codex-clawclaw 目录下 npm link');
        process.exit(1);
      }

      const addArgs = ['mcp', 'add', 'clawclaw', '--env', `CLAWCLAW_WS_URL=${wsUrl}`, '--', entry.command, ...entry.args];

      if (opts.print) {
        console.log('# 推荐执行:');
        console.log(`codex ${addArgs.join(' ')}`);
        console.log('');
        console.log('# 等价 config.toml:');
        console.log('[mcp_servers.clawclaw]');
        console.log(`command = '${entry.command.replace(/\\/g, '\\\\')}'`);
        console.log(`args = ${JSON.stringify(entry.args)}`);
        console.log('[mcp_servers.clawclaw.env]');
        console.log(`CLAWCLAW_WS_URL = '${wsUrl}'`);
        console.log('startup_timeout_sec = 30');
        return;
      }

      if (codexMcpAvailable() && codexMcpAlreadyRegistered()) {
        console.log(`ClawClaw MCP server 已注册(CLWCLAW_WS_URL=${wsUrl})。`);
        process.exit(0);
      }

      if (!opts.yes) {
        console.log('待执行:');
        console.log(`  codex ${addArgs.join(' ')}`);
        if (!codexMcpAvailable()) {
          console.log('');
          console.log('(codex mcp 不可用,将回退到直接写 config.toml)');
        }
        console.log('');
        console.log(`默认端口 ${wsPort},可用 --ws-port 指定。`);
        console.log('Dry-run 模式。加 -y 以应用更改。');
        process.exit(2);
      }

      // ── 应用: 优先 codex mcp add ──
      if (codexMcpAvailable()) {
        const r = spawnSync(resolveCodexExe()!, addArgs, {
          env: { ...process.env, NO_COLOR: '1' },
          windowsHide: true, timeout: 30_000, encoding: 'utf-8',
        });
        if (r.status !== 0) {
          console.error('codex mcp add 失败:', r.stderr?.trim() || r.stdout?.trim() || `exit ${r.status}`);
          process.exit(1);
        }
        console.log(`已注册 ClawClaw MCP server(CLAWCLAW_WS_URL=${wsUrl})。`);
        console.log('');
        console.log('下一步:');
        console.log(`  1. codex app-server --listen ${wsUrl}`);
        console.log(`  2. codex --remote ${wsUrl}`);
        console.log('  3. 在会话中说 开始一局龙虾杀(无需传参数)');
        process.exit(0);
      }

      // ── 回退: 直接写 config.toml ──
      const configPath = resolveCodexConfigPath();
      if (!existsSync(configPath)) {
        console.log('Codex config 未找到:', configPath);
        console.log('请先运行 codex 完成初始化。');
        process.exit(1);
      }

      let raw: string;
      try { raw = readFileSync(configPath, 'utf-8'); } catch (e: any) {
        console.error('读取失败:', e?.message ?? e);
        process.exit(1);
      }

      if (/^\s*\[mcp_servers\.clawclaw\]/m.test(raw)) {
        console.log('[mcp_servers.clawclaw] 已存在于 config.toml。');
        process.exit(0);
      }

      const ts = new Date().toISOString().replace(/[:.]/g, '-');
      copyFileSync(configPath, `${configPath}.bak.${ts}`);

      const snippet = [
        '',
        '[mcp_servers.clawclaw]',
        `command = '${entry.command.replace(/\\/g, '\\\\')}'`,
        `args = ${JSON.stringify(entry.args)}`,
        'startup_timeout_sec = 30',
        '',
        '[mcp_servers.clawclaw.env]',
        `CLAWCLAW_WS_URL = '${wsUrl}'`,
        '',
      ].join('\n');
      appendFileSync(configPath, snippet, 'utf-8');

      console.log(`已更新 ${configPath}(备份: config.toml.bak.${ts})`);
      console.log(`CLAWCLAW_WS_URL = ${wsUrl}`);
      console.log('');
      console.log('重启 Codex 后生效。可用工具:');
      console.log('  clawclaw_game_start / clawclaw_game_stop / clawclaw_game_status');
    });
}
