#!/usr/bin/env node
/**
 * DS2API 启动脚本 - 交互式菜单
 *
 * 使用方法:
 *   node start.mjs          # 显示交互式菜单
 *   node start.mjs dev      # 开发模式（后端+前端）
 *   node start.mjs prod     # 生产模式
 */

import { spawn, execSync } from 'child_process';
import { createInterface } from 'readline';
import { existsSync } from 'fs';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

// 判断是否为 Windows
const isWindows = process.platform === 'win32';

// 配置
const CONFIG = {
  backendPort: process.env.PORT || 5001,
  frontendPort: 5173,
  host: process.env.HOST || '0.0.0.0',
  logLevel: process.env.LOG_LEVEL || 'info',
  adminKey: process.env.DS2API_ADMIN_KEY || 'ds2api',
  webuiDir: join(__dirname, 'webui'),
  venvDir: join(__dirname, '.venv'),
};

// venv 中的可执行文件路径
const VENV = {
  python: isWindows
    ? join(CONFIG.venvDir, 'Scripts', 'python.exe')
    : join(CONFIG.venvDir, 'bin', 'python'),
  pip: isWindows
    ? join(CONFIG.venvDir, 'Scripts', 'pip.exe')
    : join(CONFIG.venvDir, 'bin', 'pip'),
};

// 存储子进程
const processes = [];

// 颜色输出
const colors = {
  reset: '\x1b[0m',
  bright: '\x1b[1m',
  dim: '\x1b[2m',
  red: '\x1b[31m',
  green: '\x1b[32m',
  yellow: '\x1b[33m',
  blue: '\x1b[34m',
  magenta: '\x1b[35m',
  cyan: '\x1b[36m',
};

const log = {
  info: (msg) => console.log(`${colors.cyan}[INFO]${colors.reset} ${msg}`),
  success: (msg) => console.log(`${colors.green}[OK]${colors.reset} ${msg}`),
  warn: (msg) => console.log(`${colors.yellow}[WARN]${colors.reset} ${msg}`),
  error: (msg) => console.log(`${colors.red}[ERROR]${colors.reset} ${msg}`),
  title: (msg) => console.log(`\n${colors.bright}${colors.magenta}${msg}${colors.reset}`),
};

// 清理并退出
function cleanup() {
  console.log('\n');
  log.info('正在关闭所有服务...');
  processes.forEach(proc => {
    if (proc && !proc.killed) {
      proc.kill('SIGTERM');
    }
  });
  log.success('已退出');
  process.exit(0);
}

// 注册退出处理
process.on('SIGINT', cleanup);
process.on('SIGTERM', cleanup);

// 检查命令是否存在
function commandExists(cmd) {
  try {
    execSync(`${isWindows ? 'where' : 'which'} ${cmd}`, { stdio: 'ignore' });
    return true;
  } catch {
    return false;
  }
}

// 获取系统 Python 命令
function getSystemPython() {
  const candidates = isWindows
    ? ['python', 'python3', 'py']
    : ['python3', 'python'];

  for (const cmd of candidates) {
    if (commandExists(cmd)) {
      return cmd;
    }
  }
  return null;
}

// 系统 Python 命令
const SYSTEM_PYTHON = getSystemPython();

// 检查 venv 是否存在
function venvExists() {
  return existsSync(VENV.python);
}

// 检查 Python 依赖是否已安装
function checkPythonDeps() {
  if (!venvExists()) return false;
  try {
    execSync(`"${VENV.python}" -c "import fastapi, uvicorn"`, {
      stdio: 'ignore',
      shell: true,
    });
    return true;
  } catch {
    return false;
  }
}

// 检查前端依赖是否已安装
function checkFrontendDeps() {
  if (!existsSync(CONFIG.webuiDir)) return null;
  return existsSync(join(CONFIG.webuiDir, 'node_modules'));
}

// 获取依赖状态
function getDepsStatus() {
  return {
    venv: venvExists(),
    python: checkPythonDeps(),
    frontend: checkFrontendDeps(),
  };
}

// 查找占用端口的进程 PID
function findPidByPort(port) {
  try {
    if (isWindows) {
      const output = execSync(`netstat -ano | findstr :${port} | findstr LISTENING`, {
        encoding: 'utf-8',
        shell: true,
        stdio: ['pipe', 'pipe', 'ignore'],
      });
      const pids = new Set();
      for (const line of output.trim().split('\n')) {
        const parts = line.trim().split(/\s+/);
        const pid = parts[parts.length - 1];
        if (pid && pid !== '0') pids.add(pid);
      }
      return [...pids];
    } else {
      const output = execSync(`lsof -ti :${port}`, {
        encoding: 'utf-8',
        stdio: ['pipe', 'pipe', 'ignore'],
      });
      return output.trim().split('\n').filter(Boolean);
    }
  } catch {
    return [];
  }
}

// 获取运行中的服务状态
function getRunningStatus() {
  const backendPids = findPidByPort(CONFIG.backendPort);
  const frontendPids = findPidByPort(CONFIG.frontendPort);
  return {
    backend: backendPids,
    frontend: frontendPids,
    isRunning: backendPids.length > 0 || frontendPids.length > 0,
  };
}

// 停止服务
async function stopServices() {
  const running = getRunningStatus();

  if (!running.isRunning) {
    log.warn('没有检测到正在运行的服务');
    return;
  }

  log.title('========== 停止服务 ==========');

  const killProcess = async (pid) => {
    try {
      if (isWindows) {
        try {
          execSync(`taskkill /PID ${pid}`, { stdio: 'ignore', shell: true });
        } catch {
          execSync(`taskkill /F /T /PID ${pid}`, { stdio: 'ignore', shell: true });
        }
      } else {
        execSync(`kill -15 ${pid}`, { stdio: 'ignore' });
        await new Promise(r => setTimeout(r, 500));
        try {
          execSync(`kill -0 ${pid}`, { stdio: 'ignore' });
          execSync(`kill -9 ${pid}`, { stdio: 'ignore' });
        } catch { /* 进程已退出 */ }
      }
    } catch { /* 进程可能已退出 */ }
  };

  if (running.backend.length > 0) {
    log.info(`停止后端服务 (端口 ${CONFIG.backendPort}, PID: ${running.backend.join(', ')})...`);
    for (const pid of running.backend) {
      await killProcess(pid);
    }
    log.success('后端服务已停止');
  }

  if (running.frontend.length > 0) {
    log.info(`停止前端服务 (端口 ${CONFIG.frontendPort}, PID: ${running.frontend.join(', ')})...`);
    for (const pid of running.frontend) {
      await killProcess(pid);
    }
    log.success('前端服务已停止');
  }
}

// 创建 venv
async function createVenv() {
  if (venvExists()) {
    log.info('虚拟环境已存在');
    return true;
  }

  if (!SYSTEM_PYTHON) {
    throw new Error('未找到 Python，请先安装 Python');
  }

  log.info('创建 Python 虚拟环境...');
  return new Promise((resolve, reject) => {
    const proc = spawn(SYSTEM_PYTHON, ['-m', 'venv', CONFIG.venvDir], {
      cwd: __dirname,
      stdio: 'inherit',
      shell: true,
    });
    proc.on('close', code => {
      if (code === 0) {
        log.success('虚拟环境创建成功');
        resolve(true);
      } else {
        reject(new Error('虚拟环境创建失败'));
      }
    });
  });
}

// 确保 venv 存在
async function ensureVenv() {
  if (!venvExists()) {
    await createVenv();
  }
}

// 确保 Python 依赖已安装
async function ensurePythonDeps() {
  await ensureVenv();
  if (!checkPythonDeps()) {
    log.warn('检测到 Python 依赖未安装，正在安装...');
    await installPythonDeps();
  }
}

// 确保前端依赖已安装
async function ensureFrontendDeps() {
  if (checkFrontendDeps() === false) {
    log.warn('检测到前端依赖未安装，正在安装...');
    await installFrontendDeps();
  }
}

// 安装 Python 依赖
async function installPythonDeps() {
  await ensureVenv();
  log.info('安装 Python 依赖...');
  return new Promise((resolve, reject) => {
    const proc = spawn(VENV.pip, ['install', '-r', 'requirements.txt'], {
      cwd: __dirname,
      stdio: 'inherit',
      shell: true,
    });
    proc.on('close', code => code === 0 ? resolve() : reject(new Error('Python 依赖安装失败')));
  });
}

// 安装前端依赖
async function installFrontendDeps() {
  if (!existsSync(CONFIG.webuiDir)) {
    log.warn('webui 目录不存在，跳过前端依赖安装');
    return;
  }
  log.info('安装前端依赖...');
  return new Promise((resolve, reject) => {
    const proc = spawn('npm', ['install'], {
      cwd: CONFIG.webuiDir,
      stdio: 'inherit',
      shell: true,
    });
    proc.on('close', code => code === 0 ? resolve() : reject(new Error('前端依赖安装失败')));
  });
}

// 安装所有依赖
async function installAll() {
  log.title('========== 安装依赖 ==========');
  try {
    await installPythonDeps();
    log.success('Python 依赖安装完成');
    await installFrontendDeps();
    log.success('前端依赖安装完成');
    log.success('所有依赖安装完成！');
  } catch (e) {
    log.error(e.message);
  }
}

// 启动后端
async function startBackend(devMode = true) {
  await ensurePythonDeps();

  log.info(`启动后端服务... http://localhost:${CONFIG.backendPort}`);

  const args = [
    '-m', 'uvicorn',
    'app:app',
    '--host', CONFIG.host,
    '--port', String(CONFIG.backendPort),
    '--log-level', CONFIG.logLevel,
  ];

  if (devMode) {
    args.push('--reload', '--reload-dir', __dirname);
  }

  const proc = spawn(VENV.python, args, {
    cwd: __dirname,
    stdio: 'inherit',
    shell: true,
    env: {
      ...process.env,
      DS2API_ADMIN_KEY: CONFIG.adminKey,
    },
  });

  processes.push(proc);
  return proc;
}

// 启动前端
async function startFrontend() {
  if (!existsSync(CONFIG.webuiDir)) {
    log.warn('webui 目录不存在，跳过前端启动');
    return null;
  }

  await ensureFrontendDeps();

  log.info(`启动前端服务... http://localhost:${CONFIG.frontendPort}`);

  const proc = spawn('npm', ['run', 'dev'], {
    cwd: CONFIG.webuiDir,
    stdio: 'inherit',
    shell: true,
  });

  processes.push(proc);
  return proc;
}

// 构建前端
async function buildFrontend() {
  if (!existsSync(CONFIG.webuiDir)) {
    log.warn('webui 目录不存在');
    return;
  }

  log.info('构建前端...');
  return new Promise((resolve, reject) => {
    const proc = spawn('npm', ['run', 'build'], {
      cwd: CONFIG.webuiDir,
      stdio: 'inherit',
      shell: true,
    });
    proc.on('close', code => code === 0 ? resolve() : reject(new Error('前端构建失败')));
  });
}

// 显示状态信息
function showStatus() {
  console.log('\n' + '─'.repeat(50));
  log.success(`后端 API:  http://localhost:${CONFIG.backendPort}`);
  if (existsSync(CONFIG.webuiDir)) {
    log.success(`管理界面: http://localhost:${CONFIG.frontendPort}`);
  }
  console.log('─'.repeat(50));
  log.info('按 Ctrl+C 停止所有服务\n');
}

// 等待进程
function waitForProcesses() {
  return new Promise(resolve => {
    const checkInterval = setInterval(() => {
      const alive = processes.filter(p => !p.killed);
      if (alive.length === 0) {
        clearInterval(checkInterval);
        resolve();
      }
    }, 1000);
  });
}

// 交互式菜单
async function showMenu() {
  const rl = createInterface({
    input: process.stdin,
    output: process.stdout,
  });

  const question = (prompt) => new Promise(resolve => rl.question(prompt, resolve));

  console.clear();
  log.title('╔══════════════════════════════════════════╗');
  log.title('║         DS2API 启动脚本                  ║');
  log.title('╚══════════════════════════════════════════╝');

  // 获取依赖状态
  const deps = getDepsStatus();
  const running = getRunningStatus();

  const statusText = (ok) => ok ? `${colors.green}已安装${colors.reset}` : `${colors.yellow}未安装${colors.reset}`;

  console.log(`\n${colors.bright}环境状态:${colors.reset}`);
  console.log(`  Python:     ${SYSTEM_PYTHON || `${colors.red}未找到${colors.reset}`}`);
  console.log(`  虚拟环境:   ${deps.venv ? `${colors.green}已创建${colors.reset}` : `${colors.yellow}未创建${colors.reset}`} (${CONFIG.venvDir})`);
  console.log(`  后端依赖:   ${statusText(deps.python)}`);
  if (deps.frontend !== null) {
    console.log(`  前端依赖:   ${statusText(deps.frontend)}`);
  }

  console.log(`\n${colors.bright}服务状态:${colors.reset}`);
  console.log(`  后端 (${CONFIG.backendPort}): ${running.backend.length > 0 ? `${colors.green}运行中${colors.reset} (PID: ${running.backend.join(', ')})` : `${colors.dim}未运行${colors.reset}`}`);
  console.log(`  前端 (${CONFIG.frontendPort}): ${running.frontend.length > 0 ? `${colors.green}运行中${colors.reset} (PID: ${running.frontend.join(', ')})` : `${colors.dim}未运行${colors.reset}`}`);

  console.log(`\n${colors.bright}管理员密钥:${colors.reset} ${colors.cyan}${CONFIG.adminKey}${colors.reset}`);
  console.log(`${colors.dim}  自定义: DS2API_ADMIN_KEY=你的密钥 node start.mjs${colors.reset}`);

  console.log(`
${colors.bright}请选择操作:${colors.reset}

  ${colors.cyan}1.${colors.reset} 开发模式 (后端 + 前端热重载)
  ${colors.cyan}2.${colors.reset} 仅启动后端 (开发模式)
  ${colors.cyan}3.${colors.reset} 仅启动前端
  ${colors.cyan}4.${colors.reset} 生产模式 (仅后端，无热重载)
  ${colors.cyan}5.${colors.reset} 构建前端
  ${colors.cyan}6.${colors.reset} 安装依赖 (创建venv + 安装包)
  ${colors.red}7.${colors.reset} 停止所有服务
  ${colors.cyan}0.${colors.reset} 退出
`);

  const choice = await question(`${colors.yellow}请输入选项 [1]: ${colors.reset}`);
  rl.close();

  switch (choice.trim() || '1') {
    case '1':
      log.title('========== 开发模式 ==========');
      await startBackend(true);
      await new Promise(r => setTimeout(r, 1500));
      await startFrontend();
      showStatus();
      await waitForProcesses();
      break;

    case '2':
      log.title('========== 仅后端 (开发模式) ==========');
      await startBackend(true);
      showStatus();
      await waitForProcesses();
      break;

    case '3':
      log.title('========== 仅前端 ==========');
      await startFrontend();
      showStatus();
      await waitForProcesses();
      break;

    case '4':
      log.title('========== 生产模式 ==========');
      await startBackend(false);
      showStatus();
      await waitForProcesses();
      break;

    case '5':
      await buildFrontend();
      log.success('前端构建完成！');
      break;

    case '6':
      await installAll();
      break;

    case '7':
      await stopServices();
      break;

    case '0':
      log.info('再见！');
      process.exit(0);
      break;

    default:
      log.warn('无效选项');
      await showMenu();
  }
}

// 命令行参数处理
async function main() {
  const args = process.argv.slice(2);
  const cmd = args[0];

  // 检查必要工具
  if (!SYSTEM_PYTHON) {
    log.error('未找到 Python，请先安装 Python (尝试了 python, python3, py)');
    process.exit(1);
  }

  switch (cmd) {
    case 'dev':
      log.title('========== 开发模式 ==========');
      await startBackend(true);
      await new Promise(r => setTimeout(r, 1500));
      await startFrontend();
      showStatus();
      await waitForProcesses();
      break;

    case 'prod':
      log.title('========== 生产模式 ==========');
      await startBackend(false);
      showStatus();
      await waitForProcesses();
      break;

    case 'build':
      await buildFrontend();
      log.success('前端构建完成！');
      break;

    case 'install':
      await installAll();
      break;

    case 'stop':
      await stopServices();
      break;

    case 'status':
      const status = getRunningStatus();
      console.log(`\n${colors.bright}服务状态:${colors.reset}`);
      console.log(`  后端 (${CONFIG.backendPort}): ${status.backend.length > 0 ? `${colors.green}运行中${colors.reset} (PID: ${status.backend.join(', ')})` : `${colors.dim}未运行${colors.reset}`}`);
      console.log(`  前端 (${CONFIG.frontendPort}): ${status.frontend.length > 0 ? `${colors.green}运行中${colors.reset} (PID: ${status.frontend.join(', ')})` : `${colors.dim}未运行${colors.reset}`}\n`);
      break;

    case 'help':
    case '-h':
    case '--help':
      console.log(`
${colors.bright}DS2API 启动脚本${colors.reset}

${colors.cyan}使用方法:${colors.reset}
  node start.mjs              显示交互式菜单
  node start.mjs dev          开发模式 (后端 + 前端)
  node start.mjs prod         生产模式 (无热重载)
  node start.mjs build        构建前端
  node start.mjs install      安装所有依赖 (自动创建venv)
  node start.mjs stop         停止所有服务
  node start.mjs status       查看服务状态

${colors.cyan}环境变量:${colors.reset}
  PORT        后端端口 (默认: 5001)
  HOST        监听地址 (默认: 0.0.0.0)
  LOG_LEVEL   日志级别 (默认: info)

${colors.cyan}虚拟环境:${colors.reset}
  默认路径: .venv/
  首次运行 install 时自动创建
`);
      break;

    default:
      await showMenu();
  }
}

main().catch(e => {
  log.error(e.message);
  process.exit(1);
});
