#!/usr/bin/env node

/**
 * fluig-mcp — Entry point principal
 *
 * Uso:
 *   npx @future-station/fluig-mcp serve    → inicia servidor MCP via stdio
 *   npx @future-station/fluig-mcp setup    → wizard de configuracao
 *   npx @future-station/fluig-mcp skills   → menu de skills
 *   npx @future-station/fluig-mcp          → wizard de setup (padrao)
 */

const { spawn, execSync } = require("child_process");
const path = require("path");
const fs = require("fs");

const RESET = "\x1b[0m";
const BOLD = "\x1b[1m";
const RED = "\x1b[31m";
const GREEN = "\x1b[32m";
const YELLOW = "\x1b[33m";
const CYAN = "\x1b[36m";

function print(msg) {
  process.stderr.write(msg + "\n");
}

function erro(msg) {
  print(`${RED}${BOLD}✗ ${msg}${RESET}`);
}

function ok(msg) {
  print(`${GREEN}${BOLD}✓ ${msg}${RESET}`);
}

function info(msg) {
  print(`${CYAN}${msg}${RESET}`);
}

// ─── Detectar Python ────────────────────────────────────────────────────────

function detectarPython() {
  const candidatos = ["python3", "python", "py"];

  for (const cmd of candidatos) {
    try {
      const resultado = execSync(`${cmd} --version 2>&1`, {
        encoding: "utf8",
        timeout: 5000,
      }).trim();

      const match = resultado.match(/Python (\d+)\.(\d+)/);
      if (match) {
        const major = parseInt(match[1]);
        const minor = parseInt(match[2]);
        if (major === 3 && minor >= 8) {
          return cmd;
        } else if (major === 3) {
          erro(
            `Python ${major}.${minor} encontrado, mas é necessário Python 3.8+`
          );
        }
      }
    } catch (_) {}
  }

  return null;
}

// ─── Encontrar pasta mcp/ ───────────────────────────────────────────────────

function encontrarMcp() {
  // 1. Relativo ao bin/ (quando instalado via npm)
  const relativoAoBin = path.join(__dirname, "..", "mcp");
  if (fs.existsSync(path.join(relativoAoBin, "server.py"))) {
    return relativoAoBin;
  }

  // 2. Diretório atual tem mcp/
  const cwd = path.join(process.cwd(), "mcp");
  if (fs.existsSync(path.join(cwd, "server.py"))) {
    return cwd;
  }

  // 3. Diretório atual tem server.py diretamente
  if (fs.existsSync(path.join(process.cwd(), "server.py"))) {
    return process.cwd();
  }

  return null;
}

// ─── Instalar dependências Python se necessário ─────────────────────────────

function garantirDependencias(python, mcpDir) {
  const reqFile = path.join(mcpDir, "requirements.txt");
  if (!fs.existsSync(reqFile)) return;

  try {
    execSync(`${python} -c "import mcp, httpx, dotenv, authlib"`, {
      encoding: "utf8",
      timeout: 5000,
      stdio: "pipe",
    });
  } catch (_) {
    info("Instalando dependências Python...");
    try {
      execSync(`${python} -m pip install -r "${reqFile}" -q`, {
        timeout: 120000,
        stdio: "inherit",
      });
      ok("Dependências instaladas");
      print("");
    } catch (err) {
      erro(`Erro ao instalar dependências: ${err.message}`);
      print(`${YELLOW}Tente manualmente: pip install -r ${reqFile}${RESET}`);
      process.exit(1);
    }
  }
}

// ─── Iniciar servidor MCP via stdio ─────────────────────────────────────────

function iniciarServidor(python, mcpDir) {
  const serverScript = path.join(mcpDir, "server.py");

  if (!fs.existsSync(serverScript)) {
    erro("server.py não encontrado.");
    process.exit(1);
  }

  // Servidor MCP: stdin/stdout são do protocolo, stderr para logs
  const proc = spawn(python, [serverScript], {
    cwd: mcpDir,
    stdio: ["pipe", "pipe", "inherit"],
    env: process.env,
  });

  // Encaminhar stdin do processo pai para o server
  process.stdin.pipe(proc.stdin);

  // Encaminhar stdout do server para o processo pai
  proc.stdout.pipe(process.stdout);

  proc.on("error", (err) => {
    process.stderr.write(`Erro ao iniciar servidor: ${err.message}\n`);
    process.exit(1);
  });

  proc.on("close", (code) => {
    process.exit(code || 0);
  });

  // Encerrar servidor se o processo pai for encerrado
  process.on("SIGINT", () => proc.kill("SIGINT"));
  process.on("SIGTERM", () => proc.kill("SIGTERM"));
}

// ─── Main ───────────────────────────────────────────────────────────────────

async function main() {
  const args = process.argv.slice(2);
  const modo = args[0] || "setup";

  // Ajuda
  if (modo === "--help" || modo === "-h" || modo === "help") {
    print("");
    print(`${BOLD}${CYAN}Fluig MCP — Future Station${RESET}`);
    print("");
    print(`${BOLD}Comandos disponíveis:${RESET}`);
    print("");
    print(
      `  ${CYAN}fluig-mcp serve${RESET}     Inicia o servidor MCP via stdio`
    );
    print(
      `  ${CYAN}fluig-mcp setup${RESET}     Wizard de configuração`
    );
    print(
      `  ${CYAN}fluig-mcp skills${RESET}    Menu de skills`
    );
    print("");
    print(`${BOLD}Modo serve:${RESET}`);
    print("  Inicia o servidor MCP usando transporte stdio.");
    print("  Use --sse para iniciar com transporte SSE (HTTP na porta 3000).");
    print("  Use este modo para conectar o MCP a clientes como Claude Code.");
    print("");
    print(`${BOLD}Modo setup:${RESET}`);
    print("  • Configura servidor Fluig e credenciais OAuth");
    print("  • Testa a conexão com o Fluig");
    print("  • Registra o MCP no Claude Code");
    print("  • Instala skills para desenvolvimento Fluig");
    print("");
    print(`${BOLD}Modo skills:${RESET}`);
    print("  • Instala skills para Claude Code, Codex CLI, Copilot e Cursor");
    print("  • Gerencia instalações existentes");
    print("");
    process.exit(0);
  }

  // Modo serve: silencioso no stdout — apenas protocolo MCP
  if (modo === "serve") {
    const useSSE = args.includes("--sse");

    const python = detectarPython();
    if (!python) {
      process.stderr.write("Python 3.8+ não encontrado.\n");
      process.exit(1);
    }

    const mcpDir = encontrarMcp();
    if (!mcpDir) {
      process.stderr.write("Pasta mcp/ não encontrada.\n");
      process.exit(1);
    }

    garantirDependencias(python, mcpDir);

    if (useSSE) {
      process.env.MCP_TRANSPORT = "sse";
      const serverScript = path.join(mcpDir, "server.py");
      const proc = spawn(python, [serverScript], {
        cwd: mcpDir,
        stdio: "inherit",
        env: process.env,
      });

      proc.on("error", (err) => {
        process.stderr.write(`Erro ao iniciar servidor SSE: ${err.message}\n`);
        process.exit(1);
      });

      proc.on("close", (code) => {
        process.exit(code || 0);
      });

      process.on("SIGINT", () => proc.kill("SIGINT"));
      process.on("SIGTERM", () => proc.kill("SIGTERM"));
    } else {
      iniciarServidor(python, mcpDir);
    }
    return;
  }

  // Modos interativos: setup e skills (Node.js — sem Python)
  if (modo === "skills") {
    const { runSkillsMenu } = require("../lib/wizard/steps/skills");
    await runSkillsMenu();
  } else {
    const { runWizard } = require("../lib/wizard/index");
    await runWizard();
  }
}

main().catch((err) => {
  if (err.name === "ExitPromptError") {
    print(`\n  ${YELLOW}Setup cancelado.${RESET}\n`);
    process.exit(0);
  }
  erro(`Erro fatal: ${err.message}`);
  process.exit(1);
});
