import express from 'express';
import { spawn } from 'child_process';
import { promises as fs } from 'fs';
import path from 'path';
import os from 'os';
import TOML from '@iarna/toml';
import { getCodexSessions, getCodexSessionMessages, deleteCodexSession } from '../projects.js';

const router = express.Router();

router.get('/config', async (req, res) => {
  try {
    const configPath = path.join(os.homedir(), '.codex', 'config.toml');
    const content = await fs.readFile(configPath, 'utf8');
    const config = TOML.parse(content);

    res.json({
      success: true,
      config: {
        model: config.model || null,
        mcpServers: config.mcp_servers || {},
        approvalMode: config.approval_mode || 'suggest'
      }
    });
  } catch (error) {
    if (error.code === 'ENOENT') {
      res.json({
        success: true,
        config: {
          model: null,
          mcpServers: {},
          approvalMode: 'suggest'
        }
      });
    } else {
      console.error('Error reading Codex config:', error);
      res.status(500).json({ success: false, error: error.message });
    }
  }
});

router.get('/sessions', async (req, res) => {
  try {
    const { projectPath } = req.query;

    if (!projectPath) {
      return res.status(400).json({ success: false, error: 'projectPath query parameter required' });
    }

    const sessions = await getCodexSessions(projectPath);
    res.json({ success: true, sessions });
  } catch (error) {
    console.error('Error fetching Codex sessions:', error);
    res.status(500).json({ success: false, error: error.message });
  }
});

router.get('/sessions/:sessionId/messages', async (req, res) => {
  try {
    const { sessionId } = req.params;
    const { limit, offset } = req.query;

    const result = await getCodexSessionMessages(
      sessionId,
      limit ? parseInt(limit, 10) : null,
      offset ? parseInt(offset, 10) : 0
    );

    res.json({ success: true, ...result });
  } catch (error) {
    console.error('Error fetching Codex session messages:', error);
    res.status(500).json({ success: false, error: error.message });
  }
});

router.delete('/sessions/:sessionId', async (req, res) => {
  try {
    const { sessionId } = req.params;
    await deleteCodexSession(sessionId);
    res.json({ success: true });
  } catch (error) {
    console.error(`Error deleting Codex session ${req.params.sessionId}:`, error);
    res.status(500).json({ success: false, error: error.message });
  }
});

// MCP Server Management Routes

router.get('/mcp/cli/list', async (req, res) => {
  try {
    const proc = spawn('codex', ['mcp', 'list'], { stdio: ['pipe', 'pipe', 'pipe'] });

    let stdout = '';
    let stderr = '';

    proc.stdout.on('data', (data) => { stdout += data.toString(); });
    proc.stderr.on('data', (data) => { stderr += data.toString(); });

    proc.on('close', (code) => {
      if (code === 0) {
        res.json({ success: true, output: stdout, servers: parseCodexListOutput(stdout) });
      } else {
        res.status(500).json({ error: 'Codex CLI command failed', details: stderr });
      }
    });

    proc.on('error', (error) => {
      res.status(500).json({ error: 'Failed to run Codex CLI', details: error.message });
    });
  } catch (error) {
    res.status(500).json({ error: 'Failed to list MCP servers', details: error.message });
  }
});

router.post('/mcp/cli/add', async (req, res) => {
  try {
    const { name, command, args = [], env = {} } = req.body;

    if (!name || !command) {
      return res.status(400).json({ error: 'name and command are required' });
    }

    // Build: codex mcp add <name> [-e KEY=VAL]... -- <command> [args...]
    let cliArgs = ['mcp', 'add', name];

    Object.entries(env).forEach(([key, value]) => {
      cliArgs.push('-e', `${key}=${value}`);
    });

    cliArgs.push('--', command);

    if (args && args.length > 0) {
      cliArgs.push(...args);
    }

    const proc = spawn('codex', cliArgs, { stdio: ['pipe', 'pipe', 'pipe'] });

    let stdout = '';
    let stderr = '';

    proc.stdout.on('data', (data) => { stdout += data.toString(); });
    proc.stderr.on('data', (data) => { stderr += data.toString(); });

    proc.on('close', (code) => {
      if (code === 0) {
        res.json({ success: true, output: stdout, message: `MCP server "${name}" added successfully` });
      } else {
        res.status(400).json({ error: 'Codex CLI command failed', details: stderr });
      }
    });

    proc.on('error', (error) => {
      res.status(500).json({ error: 'Failed to run Codex CLI', details: error.message });
    });
  } catch (error) {
    res.status(500).json({ error: 'Failed to add MCP server', details: error.message });
  }
});

router.delete('/mcp/cli/remove/:name', async (req, res) => {
  try {
    const { name } = req.params;

    const proc = spawn('codex', ['mcp', 'remove', name], { stdio: ['pipe', 'pipe', 'pipe'] });

    let stdout = '';
    let stderr = '';

    proc.stdout.on('data', (data) => { stdout += data.toString(); });
    proc.stderr.on('data', (data) => { stderr += data.toString(); });

    proc.on('close', (code) => {
      if (code === 0) {
        res.json({ success: true, output: stdout, message: `MCP server "${name}" removed successfully` });
      } else {
        res.status(400).json({ error: 'Codex CLI command failed', details: stderr });
      }
    });

    proc.on('error', (error) => {
      res.status(500).json({ error: 'Failed to run Codex CLI', details: error.message });
    });
  } catch (error) {
    res.status(500).json({ error: 'Failed to remove MCP server', details: error.message });
  }
});

router.get('/mcp/cli/get/:name', async (req, res) => {
  try {
    const { name } = req.params;

    const proc = spawn('codex', ['mcp', 'get', name], { stdio: ['pipe', 'pipe', 'pipe'] });

    let stdout = '';
    let stderr = '';

    proc.stdout.on('data', (data) => { stdout += data.toString(); });
    proc.stderr.on('data', (data) => { stderr += data.toString(); });

    proc.on('close', (code) => {
      if (code === 0) {
        res.json({ success: true, output: stdout, server: parseCodexGetOutput(stdout) });
      } else {
        res.status(404).json({ error: 'Codex CLI command failed', details: stderr });
      }
    });

    proc.on('error', (error) => {
      res.status(500).json({ error: 'Failed to run Codex CLI', details: error.message });
    });
  } catch (error) {
    res.status(500).json({ error: 'Failed to get MCP server details', details: error.message });
  }
});

router.get('/mcp/config/read', async (req, res) => {
  try {
    const configPath = path.join(os.homedir(), '.codex', 'config.toml');

    let configData = null;

    try {
      const fileContent = await fs.readFile(configPath, 'utf8');
      configData = TOML.parse(fileContent);
    } catch (error) {
      // Config file doesn't exist
    }

    if (!configData) {
      return res.json({ success: false, message: 'No Codex configuration file found', servers: [] });
    }

    const servers = [];

    if (configData.mcp_servers && typeof configData.mcp_servers === 'object') {
      for (const [name, config] of Object.entries(configData.mcp_servers)) {
        servers.push({
          id: name,
          name: name,
          type: 'stdio',
          scope: 'user',
          config: {
            command: config.command || '',
            args: config.args || [],
            env: config.env || {}
          },
          raw: config
        });
      }
    }

    res.json({ success: true, configPath, servers });
  } catch (error) {
    res.status(500).json({ error: 'Failed to read Codex configuration', details: error.message });
  }
});

function parseCodexListOutput(output) {
  const servers = [];
  const lines = output.split('\n').filter(line => line.trim());

  for (const line of lines) {
    if (line.includes(':')) {
      const colonIndex = line.indexOf(':');
      const name = line.substring(0, colonIndex).trim();

      if (!name) continue;

      const rest = line.substring(colonIndex + 1).trim();
      let description = rest;
      let status = 'unknown';

      if (rest.includes('✓') || rest.includes('✗')) {
        const statusMatch = rest.match(/(.*?)\s*-\s*([✓✗].*)$/);
        if (statusMatch) {
          description = statusMatch[1].trim();
          status = statusMatch[2].includes('✓') ? 'connected' : 'failed';
        }
      }

      servers.push({ name, type: 'stdio', status, description });
    }
  }

  return servers;
}

function parseCodexGetOutput(output) {
  try {
    const jsonMatch = output.match(/\{[\s\S]*\}/);
    if (jsonMatch) {
      return JSON.parse(jsonMatch[0]);
    }

    const server = { raw_output: output };
    const lines = output.split('\n');

    for (const line of lines) {
      if (line.includes('Name:')) server.name = line.split(':')[1]?.trim();
      else if (line.includes('Type:')) server.type = line.split(':')[1]?.trim();
      else if (line.includes('Command:')) server.command = line.split(':')[1]?.trim();
    }

    return server;
  } catch (error) {
    return { raw_output: output, parse_error: error.message };
  }
}

export default router;
