import http from 'http';
import { exec } from 'child_process';
import { chromium } from 'playwright';

const PORT = parseInt(process.env.TOOL_SERVER_PORT || '7700');
let browser = null;
let context = null;
let page = null;

const cors = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
  'Access-Control-Allow-Headers': 'Content-Type',
  'Content-Type': 'application/json',
};

function parseBody(req) {
  return new Promise((resolve) => {
    let body = '';
    req.on('data', c => body += c);
    req.on('end', () => {
      try { resolve(JSON.parse(body || '{}')); } catch { resolve({}); }
    });
  });
}

async function launchBrowser() {
  if (!browser) {
    browser = await chromium.launch({
      headless: true,
      args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage']
    });
  }
  return browser;
}

async function getPage() {
  if (!page || page.isClosed()) {
    const b = await launchBrowser();
    if (context) await context.close().catch(() => {});
    context = await b.newContext({ viewport: { width: 1280, height: 800 } });
    page = await context.newPage();
  }
  return page;
}

async function snap() {
  const p = await getPage();
  const buf = await p.screenshot({ type: 'jpeg', quality: 70, fullPage: false });
  return { screenshot: buf.toString('base64'), url: p.url(), title: await p.title() };
}

async function handleBash(body) {
  const { command, timeout = 30000 } = body;
  if (!command) return { error: 'No command provided' };
  return new Promise((resolve) => {
    exec(command, {
      timeout,
      maxBuffer: 10 * 1024 * 1024,
      cwd: process.env.WORKSPACE || process.env.HOME || '/root',
      env: { ...process.env, TERM: 'dumb', COLUMNS: '200' },
    }, (error, stdout, stderr) => {
      resolve({
        stdout: stdout || '',
        stderr: stderr || '',
        exitCode: error ? (error.code ?? 1) : 0,
        output: (stdout || '') + (stderr ? '\nSTDERR: ' + stderr : ''),
      });
    });
  });
}

async function handleNavigate(body) {
  const { url } = body;
  if (!url) return { error: 'No URL' };
  const p = await getPage();
  const target = url.startsWith('http') ? url : 'https://' + url;
  await p.goto(target, { timeout: 30000, waitUntil: 'domcontentloaded' });
  return snap();
}

async function handleClick(body) {
  const p = await getPage();
  await p.mouse.click(body.x || 0, body.y || 0);
  await p.waitForTimeout(500);
  return snap();
}

async function handleType(body) {
  const p = await getPage();
  if (body.selector) await p.fill(body.selector, body.text || '');
  else await p.keyboard.type(body.text || '');
  await p.waitForTimeout(300);
  return snap();
}

async function handleScroll(body) {
  const p = await getPage();
  await p.mouse.wheel(0, body.dy || 300);
  await p.waitForTimeout(300);
  return snap();
}

async function handleBack() {
  const p = await getPage();
  await p.goBack({ timeout: 10000 }).catch(() => {});
  return snap();
}

async function handleText() {
  const p = await getPage();
  const text = await p.evaluate(() => document.body.innerText);
  return { url: p.url(), title: await p.title(), text: text.slice(0, 8000) };
}

async function handleEval(body) {
  const p = await getPage();
  const result = await p.evaluate(body.script || 'null');
  const ss = await snap();
  return { ...ss, evalResult: String(result) };
}

const routes = {
  '/api/bash': handleBash,
  '/api/browser/navigate': handleNavigate,
  '/api/browser/click': handleClick,
  '/api/browser/type': handleType,
  '/api/browser/scroll': handleScroll,
  '/api/browser/back': handleBack,
  '/api/browser/screenshot': () => snap(),
  '/api/browser/text': handleText,
  '/api/browser/eval': handleEval,
};

http.createServer(async (req, res) => {
  if (req.method === 'OPTIONS') { res.writeHead(204, cors); res.end(); return; }
  if (req.url === '/health') { res.writeHead(200, cors); res.end(JSON.stringify({ ok: true })); return; }
  const handler = routes[req.url];
  if (req.method === 'POST' && handler) {
    try {
      const body = await parseBody(req);
      const result = await handler(body);
      res.writeHead(200, cors);
      res.end(JSON.stringify(result));
    } catch (err) {
      res.writeHead(500, cors);
      res.end(JSON.stringify({ error: String(err) }));
    }
    return;
  }
  res.writeHead(404, cors);
  res.end(JSON.stringify({ error: 'Not found' }));
}).listen(PORT, () => {
  console.log(`[tool-server] listening on :${'PORT'}`);
});
