const http = require('http');
const https = require('https');
const fs = require('fs');
const path = require('path');
const os = require('os');
const { execSync, spawn } = require('child_process');
const patcher = require('./patcher');
const agInjector = require('./ag-injector');
const zipBuilder = require('./zip-builder');

// --- CLI flags ---
const pkg = require('./package.json');
if (process.argv.includes('--version') || process.argv.includes('-v')) {
  console.log(pkg.version);
  process.exit(0);
}

// --- CLI Tools Registry ---
const CLI_TOOLS = {
  'claude-code': {
    name: 'Claude Code',
    description: 'Anthropic AI coding assistant',
    icon: 'A',
    color: '#D97706',
    command: 'claude',
    installCmd: 'npm install -g @anthropic-ai/claude-code',
    versionArg: '--version',
    category: 'npm'
  },
  'gemini-cli': {
    name: 'Gemini CLI',
    description: 'Google AI coding agent',
    icon: 'G',
    color: '#4285F4',
    command: 'gemini',
    installCmd: 'npm install -g @google/gemini-cli',
    versionArg: '--version',
    category: 'npm'
  },
  'opencode': {
    name: 'OpenCode',
    description: 'AI coding agent for terminal',
    icon: 'O',
    color: '#10B981',
    command: 'opencode',
    installCmd: 'npm install -g opencode-ai',
    versionArg: '--version',
    category: 'npm'
  },
  'codex': {
    name: 'Codex CLI',
    description: 'OpenAI coding assistant',
    icon: 'CX',
    color: '#000000',
    command: 'codex',
    installCmd: 'npm install -g @openai/codex',
    versionArg: '--version',
    category: 'npm'
  },
  'kiro': {
    name: 'Kiro CLI',
    description: 'AWS AI coding assistant',
    icon: 'K',
    color: '#FF9900',
    command: 'kiro',
    installCmdUnix: 'curl -fsSL https://cli.kiro.dev/install | bash',
    installCmdWin: null,
    versionArg: '--version',
    category: 'curl'
  },
  'aider': {
    name: 'Aider',
    description: 'AI pair programming in terminal',
    icon: 'AI',
    color: '#8B5CF6',
    command: 'aider',
    installCmd: process.platform === 'win32'
      ? 'pip install aider-chat'
      : 'pip3 install aider-chat',
    versionArg: '--version',
    category: 'pip'
  }
};

function checkToolInstalled(tool) {
  const whichCmd = process.platform === 'win32' ? 'where' : 'which';
  try {
    const cmdPath = execSync(`${whichCmd} ${tool.command}`, { encoding: 'utf8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] }).trim().split('\n')[0].trim();
    let version = '';
    try {
      version = execSync(`${tool.command} ${tool.versionArg}`, { encoding: 'utf8', timeout: 10000, stdio: ['pipe', 'pipe', 'pipe'] }).trim().split('\n')[0].trim();
    } catch (_) {}
    return { installed: true, path: cmdPath, version };
  } catch (_) {
    return { installed: false };
  }
}

function getInstallCommand(tool) {
  if (tool.category === 'curl') {
    if (process.platform === 'win32') return tool.installCmdWin;
    return tool.installCmdUnix;
  }
  return tool.installCmd;
}

const PORT = 3456;
const SETTINGS_PATH = path.join(os.homedir(), '.claude', 'settings.json');
const BACKUP_DIR = path.join(os.homedir(), '.claude', 'backups');

// --- Providers ---
const PROVIDERS = {
  anthropic: {
    name: 'Anthropic (Official)',
    description: 'API chính thức của Anthropic',
    color: '#D97706',
    baseUrl: null,
    authType: 'anthropic_key',
    defaultModels: {
      sonnet: 'claude-sonnet-4-20250514',
      opus: 'claude-opus-4-20250514',
      haiku: 'claude-haiku-4-20250414'
    }
  },
  dalink: {
    name: 'DaLink AI',
    description: 'API riêng — ai.dalink.vip',
    color: '#10B981',
    baseUrl: 'https://ai.dalink.vip/v1',
    modelsUrl: 'https://ai.dalink.vip/v1/models',
    authType: 'api_key_param',
    defaultKey: 'cacdongchi',
    defaultModels: {
      sonnet: 'gpt-5',
      opus: 'gpt-5',
      haiku: 'gpt-5-codex-mini'
    }
  },
  zai: {
    name: 'Z.AI (GLM)',
    description: 'Zhipu AI — GLM models',
    color: '#6366F1',
    baseUrl: 'https://api.z.ai/api/anthropic',
    authType: 'auth_token',
    defaultModels: {
      sonnet: 'glm-4.7',
      opus: 'glm-4.7',
      haiku: 'glm-4.5-air'
    }
  },
  openrouter: {
    name: 'OpenRouter',
    description: 'Multi-model router — openrouter.ai',
    color: '#EC4899',
    baseUrl: 'https://openrouter.ai/api/v1',
    modelsUrl: 'https://openrouter.ai/api/v1/models',
    authType: 'auth_token',
    defaultModels: {
      sonnet: 'anthropic/claude-sonnet-4-20250514',
      opus: 'anthropic/claude-opus-4-20250514',
      haiku: 'anthropic/claude-haiku-4-20250414'
    }
  },
  custom: {
    name: 'Custom Provider',
    description: 'Tự cấu hình API endpoint',
    color: '#8B5CF6',
    baseUrl: '',
    authType: 'auth_token',
    defaultModels: { sonnet: '', opus: '', haiku: '' }
  }
};

// --- Helpers ---
function readSettings() {
  try {
    if (fs.existsSync(SETTINGS_PATH)) {
      return JSON.parse(fs.readFileSync(SETTINGS_PATH, 'utf-8'));
    }
  } catch (e) {}
  return {};
}

function writeSettings(settings) {
  const dir = path.dirname(SETTINGS_PATH);
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
  fs.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2), 'utf-8');
}

function backupSettings() {
  if (!fs.existsSync(SETTINGS_PATH)) return null;
  if (!fs.existsSync(BACKUP_DIR)) fs.mkdirSync(BACKUP_DIR, { recursive: true });
  const ts = new Date().toISOString().replace(/[:.]/g, '-');
  const backupPath = path.join(BACKUP_DIR, `settings-${ts}.json`);
  fs.copyFileSync(SETTINGS_PATH, backupPath);
  return backupPath;
}

function getBackups() {
  if (!fs.existsSync(BACKUP_DIR)) return [];
  return fs.readdirSync(BACKUP_DIR)
    .filter(f => f.endsWith('.json'))
    .sort().reverse()
    .map(f => ({
      name: f,
      path: path.join(BACKUP_DIR, f),
      time: fs.statSync(path.join(BACKUP_DIR, f)).mtime
    }));
}

function fetchUrl(url, headers = {}) {
  return new Promise((resolve, reject) => {
    const mod = url.startsWith('https') ? https : http;
    const req = mod.get(url, { headers, timeout: 10000 }, (res) => {
      let data = '';
      res.on('data', chunk => data += chunk);
      res.on('end', () => {
        try { resolve(JSON.parse(data)); }
        catch { resolve(data); }
      });
    });
    req.on('error', reject);
    req.on('timeout', () => { req.destroy(); reject(new Error('Timeout')); });
  });
}

function detectCurrentProvider(settings) {
  const env = settings.env || {};
  const baseUrl = env.ANTHROPIC_BASE_URL || '';
  if (!baseUrl) return 'anthropic';
  if (baseUrl.includes('dalink.vip')) return 'dalink';
  if (baseUrl.includes('z.ai')) return 'zai';
  if (baseUrl.includes('openrouter')) return 'openrouter';
  return 'custom';
}

function readBody(req, maxSize = 1024 * 1024) {
  return new Promise((resolve, reject) => {
    let body = '';
    let size = 0;
    req.on('data', chunk => {
      size += chunk.length;
      if (size > maxSize) { req.destroy(); reject(new Error('Request body too large')); return; }
      body += chunk;
    });
    req.on('end', () => resolve(body));
    req.on('error', reject);
  });
}

function safeParseJson(str) {
  try { return { data: JSON.parse(str) }; }
  catch (e) { return { error: 'Invalid JSON: ' + e.message }; }
}

function sendJson(res, status, data) {
  res.writeHead(status, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify(data));
}

// --- Request Handler ---
async function handleRequest(req, res) {
  // SECURITY: restrict CORS to localhost only
  const origin = req.headers.origin;
  if (origin && (origin.startsWith('http://localhost:') || origin.startsWith('http://127.0.0.1:'))) {
    res.setHeader('Access-Control-Allow-Origin', origin);
  }
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
  if (req.method === 'OPTIONS') { res.writeHead(200); res.end(); return; }

  const url = new URL(req.url, `http://localhost:${PORT}`);

  // --- Serve frontend ---
  if (url.pathname === '/' || url.pathname === '/index.html') {
    const html = fs.readFileSync(path.join(__dirname, 'index.html'), 'utf-8');
    res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
    res.end(html);
    return;
  }

  // --- Serve install guide ---
  if (url.pathname === '/guide') {
    const guidePath = path.join(__dirname, 'INSTALL_GUIDE.md');
    if (fs.existsSync(guidePath)) {
      const md = fs.readFileSync(guidePath, 'utf-8');
      res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
      res.end(md);
    } else {
      res.writeHead(404); res.end('Guide not found');
    }
    return;
  }

  // --- Download ZIP package ---
  if (url.pathname === '/download') {
    try {
      const zipBuffer = zipBuilder.buildZip(__dirname);
      res.writeHead(200, {
        'Content-Type': 'application/zip',
        'Content-Disposition': `attachment; filename="ai-code-toolkits-v${pkg.version}.zip"`,
        'Content-Length': zipBuffer.length
      });
      res.end(zipBuffer);
    } catch (e) {
      res.writeHead(500, { 'Content-Type': 'application/json' });
      res.end(JSON.stringify({ error: e.message }));
    }
    return;
  }

  if (url.pathname === '/api/download/info') {
    try {
      const files = zipBuilder.collectFiles(__dirname);
      const totalSize = files.reduce((sum, f) => {
        try { return sum + fs.statSync(f.path).size; } catch (_) { return sum; }
      }, 0);
      return sendJson(res, 200, {
        version: pkg.version,
        fileCount: files.length,
        files: files.map(f => f.name),
        totalSizeBytes: totalSize,
        totalSizeFormatted: totalSize > 1024 * 1024
          ? (totalSize / (1024 * 1024)).toFixed(1) + ' MB'
          : (totalSize / 1024).toFixed(0) + ' KB'
      });
    } catch (e) {
      return sendJson(res, 500, { error: e.message });
    }
  }

  // --- Provider API ---
  if (url.pathname === '/api/providers') {
    return sendJson(res, 200, PROVIDERS);
  }

  if (url.pathname === '/api/status') {
    const settings = readSettings();
    const current = detectCurrentProvider(settings);
    return sendJson(res, 200, { current, settings, settingsPath: SETTINGS_PATH });
  }

  if (url.pathname === '/api/models') {
    const provider = url.searchParams.get('provider');
    const apiKey = url.searchParams.get('key') || '';
    const providerConfig = PROVIDERS[provider];

    if (!providerConfig || !providerConfig.modelsUrl) {
      return sendJson(res, 200, { data: [] });
    }

    try {
      let modelsUrl = providerConfig.modelsUrl;
      const headers = {};
      if (providerConfig.authType === 'api_key_param') {
        modelsUrl += `?key=${apiKey || providerConfig.defaultKey || ''}`;
      } else if (apiKey) {
        headers['Authorization'] = `Bearer ${apiKey}`;
      }
      const result = await fetchUrl(modelsUrl, headers);
      return sendJson(res, 200, result);
    } catch (e) {
      return sendJson(res, 500, { error: e.message });
    }
  }

  if (url.pathname === '/api/apply' && req.method === 'POST') {
    const parsed = safeParseJson(await readBody(req));
    if (parsed.error) return sendJson(res, 400, { success: false, error: parsed.error });
    const { provider, apiKey, baseUrl, models, timeout } = parsed.data;

    // Validate baseUrl
    if (baseUrl && !baseUrl.startsWith('http://') && !baseUrl.startsWith('https://')) {
      return sendJson(res, 400, { success: false, error: 'Base URL phải bắt đầu bằng http:// hoặc https://' });
    }

    backupSettings();
    const settings = readSettings();

    if (provider === 'anthropic') {
      if (settings.env) {
        ['ANTHROPIC_BASE_URL', 'ANTHROPIC_AUTH_TOKEN', 'ANTHROPIC_DEFAULT_SONNET_MODEL',
         'ANTHROPIC_DEFAULT_OPUS_MODEL', 'ANTHROPIC_DEFAULT_HAIKU_MODEL', 'API_TIMEOUT_MS'
        ].forEach(k => delete settings.env[k]);
        if (Object.keys(settings.env).length === 0) delete settings.env;
      }
    } else {
      if (!settings.env) settings.env = {};
      const providerUrl = baseUrl || PROVIDERS[provider]?.baseUrl || '';
      if (providerUrl) settings.env.ANTHROPIC_BASE_URL = providerUrl;
      if (apiKey) settings.env.ANTHROPIC_AUTH_TOKEN = apiKey;
      if (models?.sonnet) settings.env.ANTHROPIC_DEFAULT_SONNET_MODEL = models.sonnet;
      if (models?.opus) settings.env.ANTHROPIC_DEFAULT_OPUS_MODEL = models.opus;
      if (models?.haiku) settings.env.ANTHROPIC_DEFAULT_HAIKU_MODEL = models.haiku;
      settings.env.API_TIMEOUT_MS = timeout || '3000000';
    }

    writeSettings(settings);
    return sendJson(res, 200, { success: true, settings });
  }

  if (url.pathname === '/api/backups') {
    return sendJson(res, 200, getBackups());
  }

  if (url.pathname === '/api/restore' && req.method === 'POST') {
    const parsed = safeParseJson(await readBody(req));
    if (parsed.error) return sendJson(res, 400, { success: false, error: parsed.error });
    const { backupFile } = parsed.data;

    // SECURITY: prevent path traversal
    if (!backupFile || backupFile.includes('..') || backupFile.includes('/') || backupFile.includes('\\')) {
      return sendJson(res, 400, { error: 'Invalid backup filename' });
    }
    const backupPath = path.join(BACKUP_DIR, backupFile);
    if (!backupPath.startsWith(BACKUP_DIR) || !fs.existsSync(backupPath)) {
      return sendJson(res, 404, { error: 'Backup not found' });
    }

    backupSettings();
    fs.copyFileSync(backupPath, SETTINGS_PATH);
    return sendJson(res, 200, { success: true, settings: readSettings() });
  }

  // --- Patcher API ---
  if (url.pathname === '/api/patcher/status') {
    const cliPath = patcher.findCliJs();
    const status = patcher.checkStatus(cliPath);
    return sendJson(res, 200, status);
  }

  if (url.pathname === '/api/patcher/fix' && req.method === 'POST') {
    const parsed = safeParseJson(await readBody(req));
    if (parsed.error) return sendJson(res, 400, { success: false, error: parsed.error });
    const body = parsed.data;
    const filePath = body.path || patcher.findCliJs();

    if (!filePath) {
      return sendJson(res, 404, {
        success: false,
        error: 'Không tìm thấy Claude Code. Cài đặt: npm install -g @anthropic-ai/claude-code'
      });
    }

    const result = patcher.patch(filePath);
    return sendJson(res, result.success ? 200 : 500, result);
  }

  if (url.pathname === '/api/patcher/restore' && req.method === 'POST') {
    const parsed = safeParseJson(await readBody(req));
    if (parsed.error) return sendJson(res, 400, { success: false, error: parsed.error });
    const body = parsed.data;
    const filePath = body.path || patcher.findCliJs();

    if (!filePath) {
      return sendJson(res, 404, { success: false, error: 'Không tìm thấy Claude Code' });
    }

    const result = patcher.restore(filePath);
    return sendJson(res, result.success ? 200 : 500, result);
  }

  // --- AG Auto Click & Scroll API ---
  if (url.pathname === '/api/ag-auto/status') {
    const status = agInjector.getStatus();
    return sendJson(res, 200, status);
  }

  if (url.pathname === '/api/ag-auto/inject' && req.method === 'POST') {
    let body;
    try { body = JSON.parse(await readBody(req)); } catch { return sendJson(res, 400, { success: false, error: 'Invalid JSON' }); }
    const result = agInjector.inject(body.config || {});
    return sendJson(res, result.success ? 200 : 500, result);
  }

  if (url.pathname === '/api/ag-auto/uninstall' && req.method === 'POST') {
    const result = agInjector.uninstall();
    return sendJson(res, result.success ? 200 : 500, result);
  }

  if (url.pathname === '/api/ag-auto/config' && req.method === 'POST') {
    let body;
    try { body = JSON.parse(await readBody(req)); } catch { return sendJson(res, 400, { success: false, error: 'Invalid JSON' }); }
    const result = agInjector.updateConfig(body);
    return sendJson(res, result.success ? 200 : 500, result);
  }

  // --- CLI Installer API ---
  if (url.pathname === '/api/cli/tools') {
    return sendJson(res, 200, CLI_TOOLS);
  }

  if (url.pathname === '/api/cli/status') {
    const results = {};
    for (const [key, tool] of Object.entries(CLI_TOOLS)) {
      results[key] = {
        ...tool,
        ...checkToolInstalled(tool),
        installCommand: getInstallCommand(tool)
      };
    }
    return sendJson(res, 200, results);
  }

  if (url.pathname === '/api/cli/install' && req.method === 'POST') {
    let body;
    try { body = JSON.parse(await readBody(req)); } catch { return sendJson(res, 400, { success: false, error: 'Invalid JSON' }); }

    const toolKey = body.tool;
    const tool = CLI_TOOLS[toolKey];
    if (!tool) return sendJson(res, 400, { success: false, error: `Tool "${toolKey}" không tồn tại` });

    const installCmd = getInstallCommand(tool);
    if (!installCmd) {
      return sendJson(res, 400, { success: false, error: `${tool.name} chưa hỗ trợ trên ${process.platform === 'win32' ? 'Windows' : process.platform}` });
    }

    // Stream output via chunked transfer
    res.writeHead(200, {
      'Content-Type': 'text/plain; charset=utf-8',
      'Transfer-Encoding': 'chunked',
      'Cache-Control': 'no-cache',
      'Access-Control-Allow-Origin': '*'
    });

    res.write(`[CLI Installer] Installing ${tool.name}...\n`);
    res.write(`$ ${installCmd}\n\n`);

    const isWin = process.platform === 'win32';
    const shell = isWin ? 'cmd.exe' : '/bin/bash';
    const shellArg = isWin ? '/c' : '-c';

    const child = spawn(shell, [shellArg, installCmd], {
      stdio: ['pipe', 'pipe', 'pipe'],
      env: { ...process.env, FORCE_COLOR: '0' }
    });

    child.stdout.on('data', (data) => {
      try { res.write(data.toString()); } catch (_) {}
    });
    child.stderr.on('data', (data) => {
      try { res.write(data.toString()); } catch (_) {}
    });

    child.on('close', (code) => {
      try {
        if (code === 0) {
          res.write(`\n✅ ${tool.name} installed successfully!\n`);
        } else {
          res.write(`\n❌ Installation failed (exit code: ${code})\n`);
        }
        res.end();
      } catch (_) {}
    });

    child.on('error', (err) => {
      try {
        res.write(`\n❌ Error: ${err.message}\n`);
        res.end();
      } catch (_) {}
    });

    return;
  }

  res.writeHead(404);
  res.end('Not found');
}

// --- Start ---
const server = http.createServer(handleRequest);
server.listen(PORT, () => {
  console.log('');
  console.log('  ⚡ AI Code Toolkits');
  console.log(`  http://localhost:${PORT}`);
  console.log('');

  // Auto-detect patcher status
  try {
    const cliPath = patcher.findCliJs();
    if (cliPath) {
      const status = patcher.checkStatus(cliPath);
      console.log(`  Vietnamese Fix: ${status.patched ? '✓ Đã patch' : status.needsFix ? '✗ Cần fix' : '? Unknown'}`);
      console.log(`  CLI: ${cliPath}`);
    } else {
      console.log('  Vietnamese Fix: Claude Code chưa cài đặt');
    }
  } catch (e) {
    console.log(`  Vietnamese Fix: ${e.message}`);
  }

  // Auto-detect AG Auto status
  try {
    const agStatus = agInjector.getStatus();
    if (agStatus.found) {
      console.log(`  AG Auto: ${agStatus.injected ? '✓ Đã inject' : '✗ Chưa inject'}`);
      console.log(`  Antigravity: ${agStatus.appRoot}`);
    } else {
      console.log('  AG Auto: Antigravity chưa cài đặt');
    }
  } catch (e) {
    console.log(`  AG Auto: ${e.message}`);
  }

  console.log('');
});

// --- Global error handlers ---
process.on('uncaughtException', (err) => {
  console.error('[ERROR] Uncaught:', err.message);
});

process.on('unhandledRejection', (err) => {
  console.error('[ERROR] Unhandled rejection:', err);
});

// --- Graceful shutdown ---
process.on('SIGINT', () => {
  console.log('\n  Đang dừng server...');
  server.close(() => {
    console.log('  Server đã dừng.');
    process.exit(0);
  });
});
