/**
 * src/routes/entries.js — основные маршруты работы с белым списком IP.
 *
 * Маршруты:
 *   GET  /           — главная страница: список адресов (admin видит все компании)
 *   POST /add        — добавление новой записи
 *   POST /edit/:id   — редактирование существующей записи
 *   POST /delete/:id — удаление записи
 *
 * Все маршруты требуют авторизации (auth.middleware уже применён в server.js выше).
 * POST-маршруты дополнительно проверяются:
 *   - mutationLimiter: не более 30 запросов/мин с одного IP
 *   - doubleCsrfProtection: проверка CSRF-токена из скрытого поля формы
 *
 * Admin vs user логика:
 *   Admin (isAdmin === true, clientId === ADMIN_CLIENT_ID):
 *     - На главной видит все компании, может переключаться через ?company=<id>
 *     - В POST-запросах принимает company_id из тела формы
 *   Обычный пользователь:
 *     - Видит только свою компанию (из JWT-токена)
 *     - company_id из тела формы игнорируется (нельзя переключиться)
 *
 * @param {{ q, doubleCsrfProtection, mutationLimiter, generateCsrfToken, backUrl, requireAdmin }} deps
 * @returns {import('express').Router}
 */

'use strict';

const { Router } = require('express');

function createRouter({ q, doubleCsrfProtection, mutationLimiter, generateCsrfToken, backUrl }) {
  const router = Router();

  // ── GET / ─────────────────────────────────────────────────────────────────────
  // Главная страница: список активных CIDR для компании.
  // Admin: видит все компании + переключатель ?company=<числовой PK>.
  // User: только своя компания.
  router.get('/', async (req, res) => {
    const { clientId, companyName, isAdmin } = req.user;

    // Генерируем CSRF-токен здесь, один раз для всей страницы.
    // Он попадёт в три формы: /add, /edit (modal), /delete (каждая строка).
    const csrfToken = generateCsrfToken(req, res);

    try {
      if (isAdmin) {
        // ── Ветка admin ───────────────────────────────────────────────────────
        // Загружаем все компании (с active_count через LEFT JOIN)
        const companies = await q.getAllCompanies();

        // ?company=X — числовой PK выбранной компании.
        // Если параметра нет — берём первую компанию из списка.
        const selectedId = req.query.company
          ? parseInt(req.query.company, 10)
          : (companies[0] ? companies[0].id : null);

        // Ищем объект компании по id. Если id не найден — берём первую.
        const selectedCompany = companies.find(c => c.id === selectedId) || companies[0] || null;

        const entries = selectedCompany ? await q.listEntries(selectedCompany.id) : [];
        const limit   = selectedCompany ? await q.getLimit(selectedCompany) : 0;

        return res.render('index', {
          entries,
          limit,
          used:            entries.length,
          user:            req.user,
          isAdmin:         true,
          companies,       // для dropdown-переключателя
          selectedCompany, // текущая выбранная компания
          error:           req.query.error   || null,
          message:         req.query.message || null,
          wasNormalized:   req.query.wasNormalized === '1',
          csrfToken,
        });
      }

      // ── Ветка обычного пользователя ────────────────────────────────────────
      // getOrCreateCompany: создаёт запись в companies если её ещё нет.
      // clientId и companyName берутся из JWT (нельзя подменить через форму).
      const company = await q.getOrCreateCompany(clientId, companyName);
      const limit   = await q.getLimit(company);
      const entries = await q.listEntries(company.id);

      res.render('index', {
        entries,
        limit,
        used:            entries.length,
        user:            req.user,
        isAdmin:         false,
        companies:       null,    // пользователь не видит список компаний
        selectedCompany: company, // его единственная компания
        error:           req.query.error   || null,
        message:         req.query.message || null,
        wasNormalized:   req.query.wasNormalized === '1',
        csrfToken,
      });

    } catch (e) {
      console.error('GET / error:', e);
      // При ошибке рендерим страницу с сообщением, не падаем с 500
      res.render('index', {
        entries: [], limit: 15, used: 0,
        user: req.user, isAdmin,
        companies: null, selectedCompany: null,
        error:    'Ошибка загрузки данных: ' + e.message,
        message:  null,
        wasNormalized: false,
        csrfToken,
      });
    }
  });

  // ── POST /add ─────────────────────────────────────────────────────────────────
  // Добавление новой записи в белый список.
  // createEntry: валидирует CIDR, проверяет лимит, пишет в audit_log (транзакция).
  router.post('/add', mutationLimiter, doubleCsrfProtection, async (req, res) => {
    const { value, comment } = req.body;
    const { clientId, companyName, email, isAdmin } = req.user;

    let company;
    try {
      // Определяем компанию: admin — из скрытого поля company_id,
      // обычный пользователь — только своя (из токена, нельзя подменить).
      if (isAdmin && req.body.company_id) {
        const id = parseInt(req.body.company_id, 10);
        if (!Number.isFinite(id) || id <= 0) throw new Error('Некорректный company_id');
        company = await q.getCompanyById(id);
        if (!company) throw new Error('Компания не найдена');
      } else {
        company = await q.getOrCreateCompany(clientId, companyName);
      }

      // createEntry возвращает { entry, wasNormalized }
      // wasNormalized=true если IP был нормализован (напр. 192.168.1.1/24 → 192.168.1.0/24)
      const result = await q.createEntry(company.id, value, comment, email);
      const msg = result.wasNormalized
        ? `Адрес нормализован в ${result.entry.value_cidr}`
        : 'Добавлено';

      res.redirect(backUrl(isAdmin, company.id, {
        message:      msg,
        wasNormalized: result.wasNormalized ? '1' : '0',
      }));
    } catch (e) {
      // Ошибки: лимит исчерпан, дубликат, невалидный CIDR, etc.
      const cid = company ? company.id : req.body.company_id;
      res.redirect(backUrl(isAdmin, cid, { error: e.message }));
    }
  });

  // ── POST /edit/:id ────────────────────────────────────────────────────────────
  // Обновление существующей записи.
  // updateEntry: валидирует CIDR, проверяет принадлежность записи компании,
  //              пишет в audit_log (транзакция).
  router.post('/edit/:id', mutationLimiter, doubleCsrfProtection, async (req, res) => {
    const { value, comment } = req.body;
    const { clientId, companyName, email, isAdmin } = req.user;

    // parseInt с radix=10 — защита от октальных и hex-значений
    const entryId = parseInt(req.params.id, 10);

    let company;
    try {
      if (isAdmin && req.body.company_id) {
        const id = parseInt(req.body.company_id, 10);
        if (!Number.isFinite(id) || id <= 0) throw new Error('Некорректный company_id');
        company = await q.getCompanyById(id);
        if (!company) throw new Error('Компания не найдена');
      } else {
        company = await q.getOrCreateCompany(clientId, companyName);
      }

      const result = await q.updateEntry(entryId, company.id, value, comment, email);
      const msg = result.wasNormalized
        ? `Адрес нормализован в ${result.entry.value_cidr}`
        : 'Сохранено';

      res.redirect(backUrl(isAdmin, company.id, {
        message:      msg,
        wasNormalized: result.wasNormalized ? '1' : '0',
      }));
    } catch (e) {
      const cid = company ? company.id : req.body.company_id;
      res.redirect(backUrl(isAdmin, cid, { error: e.message }));
    }
  });

  // ── POST /delete/:id ─────────────────────────────────────────────────────────
  // Удаление записи.
  // deleteEntry: проверяет принадлежность записи компании, пишет в audit_log.
  router.post('/delete/:id', mutationLimiter, doubleCsrfProtection, async (req, res) => {
    const { clientId, companyName, email, isAdmin } = req.user;
    const entryId = parseInt(req.params.id, 10);

    let company;
    try {
      if (isAdmin && req.body.company_id) {
        const id = parseInt(req.body.company_id, 10);
        if (!Number.isFinite(id) || id <= 0) throw new Error('Некорректный company_id');
        company = await q.getCompanyById(id);
        if (!company) throw new Error('Компания не найдена');
      } else {
        company = await q.getOrCreateCompany(clientId, companyName);
      }

      await q.deleteEntry(entryId, company.id, email);
      res.redirect(backUrl(isAdmin, company.id, { message: 'Запись удалена' }));
    } catch (e) {
      const cid = company ? company.id : req.body.company_id;
      res.redirect(backUrl(isAdmin, cid, { error: e.message }));
    }
  });

  return router;
}

module.exports = { createRouter };
