import path from 'node:path';
import https from 'node:https';
import { spawn } from 'node:child_process';
import { writeFile, readFile } from 'node:fs/promises';
import { readBody, sendJSON } from '../utils/http.js';
import { isChromeDebugReachable } from '../services/chrome.js';
import { jobs } from '../server/job-store.js';
import { startJob, CLAUDE_BIN } from '../server/job-runner.js';

// Trello queue state (module-level singletons)
const trelloPendingCards = [];
let trelloCardSeq = 0;

export async function handle(req, res, url, ctx) {
  const { cwd } = ctx;

  // POST /api/notify/gchat — envia mensagem para o Google Chat space
  if (req.method === 'POST' && url.pathname === '/api/notify/gchat') {
    try {
      const { text } = JSON.parse(await readBody(req));
      const cfg = JSON.parse(await readFile(path.join(cwd, '.sdd', 'gchat-config.json'), 'utf8'));
      if (!cfg.webhookUrl) { sendJSON(res, { error: 'Webhook não configurado' }, 400); return true; }
      const webhookUrl = new URL(cfg.webhookUrl);
      const body = JSON.stringify({ text });
      const options = {
        hostname: webhookUrl.hostname,
        path: webhookUrl.pathname + webhookUrl.search,
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) }
      };
      await new Promise((resolve, reject) => {
        const req2 = https.request(options, (r) => {
          r.resume();
          r.on('end', resolve);
        });
        req2.on('error', reject);
        req2.setTimeout(8000, () => { req2.destroy(); reject(new Error('timeout')); });
        req2.write(body);
        req2.end();
      });
      sendJSON(res, { ok: true });
    } catch(e) { sendJSON(res, { error: e.message }, 500); }
    return true;
  }

  // POST /api/open-terminal
  if (req.method === 'POST' && url.pathname === '/api/open-terminal') {
    try {
      const { command } = JSON.parse(await readBody(req));
      const { execSync } = await import('node:child_process');
      const lines = String(command).split('\n').filter(Boolean);
      const shellCmd = 'cd ' + cwd + ' && ' + lines.join(' && ');
      const escaped = shellCmd.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
      execSync(`osascript -e 'tell application "Terminal" to activate' -e 'tell application "Terminal" to do script "${escaped}"'`);
      sendJSON(res, { ok: true });
    } catch (e) { sendJSON(res, { error: e.message }, 500); }
    return true;
  }

  // POST /api/open-file
  if (req.method === 'POST' && url.pathname === '/api/open-file') {
    try {
      const body = await readBody(req);
      const { file } = JSON.parse(body);
      const abs = path.resolve(cwd, file);
      spawn('code', [abs], { detached: true, stdio: 'ignore' }).unref();
      sendJSON(res, { ok: true });
    } catch (e) {
      sendJSON(res, { error: e.message }, 500);
    }
    return true;
  }

  // POST /api/execute
  if (req.method === 'POST' && url.pathname === '/api/execute') {
    try {
      const body = await readBody(req);
      const { command, approveSpec } = JSON.parse(body);
      if (approveSpec) {
        try {
          const specJsonPath = path.join(process.cwd(), '.sdd', 'specs', approveSpec, 'spec.json');
          const raw = await readFile(specJsonPath, 'utf8');
          const spec = JSON.parse(raw);
          if (!spec.approvals) spec.approvals = {};
          if (!spec.approvals.tasks) spec.approvals.tasks = {};
          spec.approvals.tasks.approved = true;
          await writeFile(specJsonPath, JSON.stringify(spec, null, 2), 'utf8');
        } catch { /* non-fatal — spec-impl will report if still missing */ }
      }
      const isSddStep = /^\/(sdd:|)spec-(requirements|design|tasks|impl)|^\/sdd:validate-gap/.test(command);
      const jobId = startJob(command, { fast: isSddStep });
      sendJSON(res, { jobId });
    } catch (e) {
      sendJSON(res, { error: e.message }, 500);
    }
    return true;
  }

  // GET /api/stream/:jobId → SSE
  const m = url.pathname.match(/^\/api\/stream\/(.+)$/);
  if (req.method === 'GET' && m) {
    const job = jobs.get(m[1]);
    if (!job) { res.writeHead(404); res.end(); return true; }

    res.writeHead(200, {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
      'Connection': 'keep-alive',
    });

    const send = (ev) => res.write('data: ' + JSON.stringify(ev) + '\n\n');

    // Replay buffered output
    for (const chunk of job.chunks) send(chunk);

    if (job.done) { send({ type: 'done', code: job.code }); res.end(); return true; }

    // Keepalive heartbeat — prevents browser/proxy from closing idle SSE after ~60s
    const heartbeat = setInterval(() => { try { res.write(': ping\n\n'); } catch { clearInterval(heartbeat); } }, 15000);

    const listener = (ev) => { send(ev); if (ev.type === 'done' || ev.type === 'error') { clearInterval(heartbeat); res.end(); } };
    job.listeners.add(listener);
    req.on('close', () => { clearInterval(heartbeat); job.listeners.delete(listener); });
    return true;
  }

  // GET /api/local/files — lista arquivos do projeto local para seleção de contexto
  if (req.method === 'GET' && url.pathname === '/api/local/files') {
    try {
      const { execSync } = await import('node:child_process');
      const SRC_EXTS = /\.(js|ts|jsx|tsx|vue|svelte|py|go|java|cs|rb|php|rs|swift|kt|c|cpp|h|hpp|md|json|yaml|yml|toml|sql|graphql|sh|html|css|scss|sass)$/i;
      const IGNORE = /(node_modules|\.git|dist|build|\.next|\.nuxt|coverage|__pycache__|vendor|\.cache|\.turbo|out\/|tmp\/|\.vscode|\.idea)/;
      let raw = '';
      try { raw = execSync('find . -type f | sort', { cwd, encoding: 'utf8', maxBuffer: 4 * 1024 * 1024 }); } catch {}
      const files = raw.trim().split('\n')
        .map(f => f.replace(/^\.\//, ''))
        .filter(f => f && !IGNORE.test(f) && (SRC_EXTS.test(f) || ['package.json','go.mod','Cargo.toml','pyproject.toml','.env.example'].includes(f)));
      sendJSON(res, { files });
    } catch (e) { sendJSON(res, { error: e.message }, 500); }
    return true;
  }

  // GET /api/debug
  if (req.method === 'GET' && url.pathname === '/api/debug') {
    const chromeReachable = await isChromeDebugReachable();
    sendJSON(res, { claudeBin: CLAUDE_BIN, chromeReachable, platform: process.platform });
    return true;
  }

  // POST /api/wi/regen-criteria — regenera critérios de aceite com base no título + descrição editados
  if (req.method === 'POST' && url.pathname === '/api/wi/regen-criteria') {
    try {
      const { title, description } = JSON.parse(await readBody(req));
      if (!description?.trim() && !title?.trim()) { sendJSON(res, { error: 'Título ou descrição obrigatório' }, 400); return true; }
      const prompt = `Você é um analista de requisitos sênior. Com base no work item abaixo, gere critérios de aceite claros e verificáveis.

Título: ${(title || '').trim()}
Descrição: ${(description || '').trim()}

Instruções:
- Gere entre 3 e 6 critérios de aceite objetivos
- Cada critério deve ser verificável por um desenvolvedor ou testador
- Use linguagem de comportamento: "Deve...", "Quando... então..."
- Responda APENAS com os critérios, um por linha, sem JSON, sem bullets, sem numeração`;

      const result = await new Promise(resolve => {
        const proc = spawn(CLAUDE_BIN, ['--print', '--dangerously-skip-permissions', prompt], {
          cwd, stdio: ['ignore', 'pipe', 'pipe'],
        });
        let out = '';
        proc.stdout.on('data', d => { out += d.toString(); });
        proc.on('close', () => resolve({ criteria: out.trim() }));
        proc.on('error', () => resolve({ error: 'Claude não disponível' }));
        setTimeout(() => { try { proc.kill(); } catch {} }, 60000);
      });
      sendJSON(res, result);
    } catch (e) { sendJSON(res, { error: e.message }, 500); }
    return true;
  }

  // POST /api/trello/queue-card
  if (req.method === 'POST' && url.pathname === '/api/trello/queue-card') {
    try {
      const body = JSON.parse(await readBody(req));
      const id = ++trelloCardSeq;
      trelloPendingCards.push({ id, name: (body.name || '').slice(0, 200), desc: (body.desc || '').slice(0, 4000), at: Date.now() });
      sendJSON(res, { ok: true, id });
    } catch (e) { sendJSON(res, { error: e.message }, 400); }
    return true;
  }

  // GET /api/trello/pending-cards
  if (req.method === 'GET' && url.pathname === '/api/trello/pending-cards') {
    sendJSON(res, { cards: trelloPendingCards });
    return true;
  }

  // DELETE /api/trello/pending-cards/:id
  if (req.method === 'DELETE' && url.pathname.startsWith('/api/trello/pending-cards/')) {
    const id = parseInt(url.pathname.split('/').pop(), 10);
    const idx = trelloPendingCards.findIndex(c => c.id === id);
    if (idx !== -1) trelloPendingCards.splice(idx, 1);
    sendJSON(res, { ok: true });
    return true;
  }

  return false;
}
