const express = require('express');
const rateLimit = require('express-rate-limit');
const router = express.Router();
const db = require('../lib/db');
const log = require('../lib/logger');

// Public API — used by landing and dashboard to load dynamic content.
// These run BEFORE authMiddleware and share the small DB pool, so rate-limit them.
const publicLimiter = rateLimit({
  keyGenerator: (req) => (req.session && req.session.user && req.session.user.id) ? 'user_' + req.session.user.id : req.ip,
  windowMs: 60 * 1000,
  max: 60,
  standardHeaders: true,
  legacyHeaders: false,
  message: { error: 'Слишком много запросов' },
});

// Get all settings as key-value object
router.get('/settings', publicLimiter, async (req, res) => {
  try {
    const [rows] = await db.pool.execute('SELECT setting_key, setting_value FROM settings');
    const settings = {};
    for (const r of rows) settings[r.setting_key] = r.setting_value;
    res.json(settings);
  } catch (err) {
    log.error('api /settings error', { error: err.message });
    res.status(500).json({ error: 'Внутренняя ошибка' });
  }
});

// Get categories with their tools
router.get('/tools', publicLimiter, async (req, res) => {
  try {
    const [categories] = await db.pool.execute('SELECT * FROM categories ORDER BY sort_order');
    const [tools] = await db.pool.execute('SELECT * FROM tools WHERE is_enabled = 1 ORDER BY sort_order');

    const result = categories.map(cat => ({
      ...cat,
      tools: tools.filter(t => t.category_id === cat.id),
    }));

    res.json(result);
  } catch (err) {
    log.error('api /tools error', { error: err.message });
    res.status(500).json({ error: 'Внутренняя ошибка' });
  }
});

// Get content blocks by section
router.get('/content/:section', publicLimiter, async (req, res) => {
  try {
    const [rows] = await db.pool.execute(
      'SELECT block_key, title, body, sort_order FROM content_blocks WHERE section = ? AND is_visible = 1 ORDER BY sort_order',
      [req.params.section]
    );
    res.json(rows);
  } catch (err) {
    log.error('api /content error', { error: err.message });
    res.status(500).json({ error: 'Внутренняя ошибка' });
  }
});


// AI explain regex (proxies to local llama.cpp)
const aiLimiter = rateLimit({
  keyGenerator: (req) => (req.session && req.session.user && req.session.user.id) ? 'user_' + req.session.user.id : req.ip,
  windowMs: 60000, max: 10, message: { error: 'Слишком много запросов к AI' },
});

router.post('/ai/explain', express.json(), aiLimiter, async (req, res) => {
  const { pattern, flags } = req.body;
  if (!pattern || typeof pattern !== 'string' || pattern.length > 5000) {
    return res.status(400).json({ error: 'Паттерн пустой или слишком длинный' });
  }

  let messages;

  if (flags === 'security-audit') {
    // Security audit mode — pattern contains full HTTP response info
    messages = [
      { role: 'system', content: 'Ты эксперт по веб-безопасности. Отвечай на русском, markdown. Будь КРАТОК — только реальные проблемы, не перечисляй то что настроено правильно. Максимум 5 пунктов.' },
      { role: 'user', content: `Проведи security-аудит этого HTTP-ответа:

${pattern}

Ответь КРАТКО по структуре:

## Оценка: [КРИТИЧНО / СРЕДНЕ / ХОРОШО]

## Проблемы (только реальные, макс 5):
- Проблема → как исправить (одной строкой)

## Что ОК (одной строкой, перечислением):
- Какие заголовки безопасности настроены правильно

НЕ разбирай каждый заголовок отдельно. НЕ повторяйся. Только практичные проблемы.` },
    ];
  } else {
    // Regex explain mode
    messages = [
      { role: 'system', content: 'Ты эксперт по регулярным выражениям. Отвечай на русском. Формат ответа: markdown без обёртки в блок кода.' },
      { role: 'user', content: `Regex: /${pattern}/${flags || 'g'}

1. Одним предложением: что это выражение ДЕЛАЕТ? Какую задачу решает?
2. Примеры строк которые СОВПАДУТ с этим выражением (2-3 примера)
3. Примеры строк которые НЕ совпадут (2-3 примера)
4. Разбор по частям (кратко, таблицей): часть паттерна → что значит` },
    ];
  }

  // SSE streaming
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');
  res.flushHeaders();

  try {
    const controller = new AbortController();
    const timeout = setTimeout(() => controller.abort(), 120000);

    // AI endpoints: PC (powerful) → RPi (fallback)
    const AI_ENDPOINTS = [
      { url: 'http://192.168.31.100:11434/v1/chat/completions', model: 'qwen2.5:14b', name: 'PC' },
      { url: 'http://127.0.0.1:8080/v1/chat/completions', model: 'qwen2.5-3b', name: 'RPi' },
    ];

    let response = null;
    let usedEndpoint = null;

    for (const ep of AI_ENDPOINTS) {
      try {
        const pingCtrl = new AbortController();
        const pingTimeout = setTimeout(() => pingCtrl.abort(), 3000);
        const ping = await fetch(ep.url.replace('/v1/chat/completions', '/v1/models'), { signal: pingCtrl.signal });
        clearTimeout(pingTimeout);
        if (!ping.ok) continue;

        response = await fetch(ep.url, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          signal: controller.signal,
          body: JSON.stringify({
            model: ep.model,
            messages,
            max_tokens: 1000,
            temperature: 0.3,
            stream: true,
          }),
        });
        usedEndpoint = ep;
        break;
      } catch (pingErr) {
        continue; // try next endpoint
      }
    }

    if (!response) {
      res.write('data: {"error":"Все AI серверы недоступны"}\n\n');
      res.end();
      return;
    }

    clearTimeout(timeout);

    if (!response.ok) {
      let errMsg = 'LLM API error: ' + response.status;
      try { const errBody = await response.text(); console.error('LLM error:', response.status, errBody.slice(0, 300)); } catch {}
      res.write('data: {"error":"' + errMsg + '"}\n\n');
      res.end();
      return;
    }

    // Pipe SSE chunks from llama.cpp to client using async iteration
    try {
      for await (const chunk of response.body) {
        const text = typeof chunk === 'string' ? chunk : Buffer.from(chunk).toString();
        res.write(text);
      }
    } catch (streamErr) {
      res.write('data: {"error":"Stream error"}\n\n');
    }
    res.write('data: [DONE]\n\n');
    res.end();

    req.on('close', () => {
      controller.abort();
    });

  } catch (err) {
    if (err.name === 'AbortError') {
      res.write('data: {"error":"AI не ответил за 2 минуты"}\n\n');
    } else {
      res.write('data: {"error":"AI недоступен"}\n\n');
    }
    res.end();
  }
});

module.exports = router;
