'use strict';
process.env.WALL_E_PROCESS_ROLE = process.env.WALL_E_PROCESS_ROLE || 'walle-daemon';

const http = require('http');
const { handleWalleApi } = require('./api-walle');
const { getAllowedOrigin, isAuthorizedRequest } = require('./http/auth');
const { startPortkeyModelSyncLoop } = require('./llm/portkey-sync');

const PORT = parseInt(process.env.WALL_E_PORT) || 3457;
const HOST = process.env.WALL_E_HOST || '127.0.0.1';

function isMcpAutoConfigDisabled() {
  const value = String(process.env.WALLE_MCP_AUTO_CONFIG || '').toLowerCase();
  return value === '0' || value === 'false' || value === 'off';
}

function autoConfigureWallEMcp() {
  if (isMcpAutoConfigDisabled()) return;
  try {
    const { ensureMcpIntegrations, getMcpAutoConfigSkipReason } = require('./lib/mcp-integration');
    if (getMcpAutoConfigSkipReason(process.env)) return;
    const results = ensureMcpIntegrations(PORT);
    const changed = results.filter(r => r.kind === 'mcp_config' && (r.action === 'added' || r.action === 'updated'));
    const instructionChanged = results.filter(r => r.kind === 'agent_instructions' && (r.action === 'added' || r.action === 'updated'));
    const errors = results.filter(r => r.action === 'error');
    if (changed.length) {
      console.log(`[wall-e] Auto-configured Wall-E MCP for ${changed.length} AI tool(s)`);
    }
    if (instructionChanged.length) {
      console.log(`[wall-e] Updated Wall-E memory-routing instructions for ${instructionChanged.length} AI agent(s)`);
    }
    if (errors.length) {
      console.warn(`[wall-e] Wall-E MCP auto-config skipped ${errors.length} invalid config file(s): ${errors.map(r => r.tool).join(', ')}`);
    }
  } catch (err) {
    console.warn(`[wall-e] Wall-E MCP auto-config failed: ${err.message}`);
  }
}

function startServer(options = {}) {
  const server = http.createServer(async (req, res) => {
    const url = new URL(req.url, `http://${req.headers.host}`);
    const apiToken = process.env.WALL_E_API_TOKEN || '';
    const allowedOrigin = getAllowedOrigin(req);

    // CORS for CTM frontend
    res.setHeader('Access-Control-Allow-Origin', allowedOrigin);
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, Accept, Mcp-Session-Id, MCP-Protocol-Version');

    if (req.method === 'OPTIONS') {
      res.writeHead(204);
      res.end();
      return;
    }

    if (!isAuthorizedRequest(req, url.pathname, apiToken)) {
      const body = JSON.stringify({ error: 'Unauthorized' });
      res.writeHead(401, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) });
      res.end(body);
      return;
    }

    // MCP Streamable HTTP endpoint
    if (url.pathname === '/mcp' && req.method === 'POST') {
      const { handleMcp } = require('./mcp-server');
      await handleMcp(req, res);
      return;
    }
    if (url.pathname === '/mcp') {
      res.writeHead(405, { Allow: 'POST' });
      res.end();
      return;
    }

    // Task stop endpoint — must be in this process (has the child process reference)
    const taskStopMatch = url.pathname.match(/^\/api\/wall-e\/tasks\/([^/]+)\/stop$/);
    if (taskStopMatch && req.method === 'POST') {
      try {
        const { stopTask } = require('./loops/tasks');
        const stopped = stopTask(taskStopMatch[1]);
        const body = JSON.stringify({ data: { stopped } });
        res.writeHead(200, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) });
        res.end(body);
      } catch (e) {
        const body = JSON.stringify({ error: e.message });
        res.writeHead(500, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) });
        res.end(body);
      }
      return;
    }

    // Immediate task run endpoint — triggers execution and returns immediately
    const taskRunNowMatch = url.pathname.match(/^\/api\/wall-e\/tasks\/([^/]+)\/run-now$/);
    if (taskRunNowMatch && req.method === 'POST') {
      try {
        const { runTaskById } = require('./loops/tasks');
        // Fire and forget — respond immediately, task runs in background
        runTaskById(taskRunNowMatch[1]).catch(e => {
          console.error('[wall-e] run-now background error:', e.message);
        });
        const body = JSON.stringify({ data: { started: true } });
        res.writeHead(200, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) });
        res.end(body);
      } catch (e) {
        const body = JSON.stringify({ error: e.message });
        res.writeHead(500, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) });
        res.end(body);
      }
      return;
    }

    // Task logs endpoint — must be in this process (in-memory buffer)
    const taskLogsMatch = url.pathname.match(/^\/api\/wall-e\/tasks\/([^/]+)\/logs$/);
    if (taskLogsMatch && req.method === 'GET') {
      try {
        const { getTaskLogs } = require('./loops/tasks');
        const logs = getTaskLogs(taskLogsMatch[1]);
        const body = JSON.stringify({ data: logs || { lines: [], status: 'unknown' } });
        res.writeHead(200, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) });
        res.end(body);
      } catch (e) {
        const body = JSON.stringify({ error: e.message });
        res.writeHead(500, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) });
        res.end(body);
      }
      return;
    }

    // Route to WALL-E API
    const handled = handleWalleApi(req, res, url);
    if (handled !== false) return;

    // 404 for everything else
    res.writeHead(404, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ error: 'Not found' }));
  });

  // Retry with exponential backoff on EADDRINUSE (port not freed yet after restart)
  let readyResolve;
  let readyReject;
  server.ready = new Promise((resolve, reject) => {
    readyResolve = resolve;
    readyReject = reject;
  });

  let retryCount = 0;
  const MAX_RETRIES = Number.isFinite(options.maxRetries) ? options.maxRetries : 6;       // up to ~30s total wait
  const BASE_DELAY_MS = Number.isFinite(options.baseDelayMs) ? options.baseDelayMs : 1000; // 1s, 2s, 4s, 8s, 8s, 8s
  const onBindFailure = typeof options.onBindFailure === 'function'
    ? options.onBindFailure
    : ((err) => process.exit(err && err.code === 'EADDRINUSE' ? 98 : 1));

  function tryListen() {
    server.listen(PORT, HOST, () => {
      if (retryCount > 0) console.log(`[wall-e] Port ${PORT} freed after ${retryCount} retries`);
      console.log(`[wall-e] HTTP server listening on ${HOST}:${PORT}`);
      readyResolve();
      if (typeof setImmediate === 'function') setImmediate(autoConfigureWallEMcp);
      else setTimeout(autoConfigureWallEMcp, 0);
      if (process.env.WALLE_DISABLE_PORTKEY_SYNC !== '1') {
        try {
          server.stopPortkeyModelSync = startPortkeyModelSyncLoop();
        } catch (err) {
          console.warn(`[wall-e] Portkey model sync loop failed to start: ${err.message}`);
        }
      }
    });
  }

  server.on('error', (err) => {
    if (err.code === 'EADDRINUSE') {
      retryCount++;
      if (retryCount > MAX_RETRIES) {
        console.error(`[wall-e] Port ${PORT} still in use after ${MAX_RETRIES} retries — exiting to avoid duplicate background loops.`);
        try { require('./telemetry').track('walle_eaddrinuse', { port: PORT, retries: retryCount }); } catch {}
        readyReject(err);
        try { server.close(); } catch {}
        onBindFailure(err);
        return;
      }
      const delay = Math.min(BASE_DELAY_MS * Math.pow(2, retryCount - 1), 8000);
      console.error(`[wall-e] Port ${PORT} in use — retry ${retryCount}/${MAX_RETRIES} in ${delay}ms...`);
      setTimeout(tryListen, delay);
    } else {
      console.error('[wall-e] Server error:', err.message);
      readyReject(err);
    }
  });
  server.on('close', () => {
    try {
      if (typeof server.stopPortkeyModelSync === 'function') server.stopPortkeyModelSync();
    } catch {}
  });

  tryListen();
  return server;
}

module.exports = { startServer, autoConfigureWallEMcp };
