'use strict';

const express = require('express');
const { aggregateCIDRs } = require('../../validators');

function createEntriesRouter({ q }) {
  const router = express.Router();
  const json = express.json({ limit: '32kb' });

  // Маппинг сообщений ошибок на HTTP-коды
  function handleQueryError(e, res) {
    const msg = e.message || '';
    // 409: бизнес-конфликты (дубликат, пересечение, лимит)
    if (
      msg.includes('Лимит исчерпан') ||
      msg.includes('Такой адрес уже существует') ||
      msg.includes('Пересечение с существующей записью')
    ) {
      return res.status(409).json({ error: msg });
    }
    // 404: запись не найдена
    if (msg.includes('Запись не найдена')) {
      return res.status(404).json({ error: msg });
    }
    // 400: ошибки валидации от validate() и blocked-ranges
    if (
      msg.includes('Некорректн') ||
      msg.includes('Маска должна быть') ||
      msg.includes('Пустое значение') ||
      msg.includes('IPv6 не поддерживается') ||
      msg.includes('пересекается с запрещённым')
    ) {
      return res.status(400).json({ error: msg });
    }
    return res.status(500).json({ error: msg });
  }

  // Определить компанию из запроса.
  // Admin с ?company=<id> → компания по ID.
  // User с ?client_id=<id> (мульти-компания) → компания по clientId.
  // Иначе → компания пользователя (UPSERT).
  async function resolveCompany(req) {
    if (req.user.isAdmin && req.query.company) {
      const id = parseInt(req.query.company, 10);
      if (!Number.isFinite(id) || id <= 0) {
        throw Object.assign(new Error('Invalid company id'), { status: 400 });
      }
      const c = await q.getCompanyById(id);
      if (!c) throw Object.assign(new Error('Company not found'), { status: 404 });
      return c;
    }
    // Мульти-компания: client_id разрешён только если есть в allClientIds пользователя
    const requestedId = (req.query.client_id || '').trim();
    const effectiveClientId = (requestedId && req.user.allClientIds && req.user.allClientIds.includes(requestedId))
      ? requestedId
      : req.user.clientId;
    // companyName: для переключённой компании — clientId как имя по умолчанию
    const effectiveName = effectiveClientId === req.user.clientId
      ? req.user.companyName
      : effectiveClientId;
    return q.getOrCreateCompany(effectiveClientId, effectiveName);
  }

  // GET /api/v1/entries — список записей + лимит
  // ?includeDeleted=true — показать soft-deleted (только admin)
  router.get('/', async (req, res) => {
    try {
      const company = await resolveCompany(req);
      const includeDeleted = req.user.isAdmin && req.query.includeDeleted === 'true';
      const [entries, limit] = await Promise.all([
        q.listEntries(company.id, includeDeleted),
        q.getLimit(company),
      ]);
      res.json({ entries, limit, used: entries.length });
    } catch (e) {
      res.status(e.status || 500).json({ error: e.message });
    }
  });

  // GET /api/v1/entries/export — агрегированный список CIDR (text/plain)
  // Доступен всем аутентифицированным пользователям.
  // Admin: все компании или ?company=<id>. User: только своя компания или ?client_id=<id>.
  router.get('/export', async (req, res) => {
    try {
      let companyId = null;
      if (!req.user.isAdmin) {
        const requestedId = (req.query.client_id || '').trim();
        const effectiveClientId = (requestedId && req.user.allClientIds && req.user.allClientIds.includes(requestedId))
          ? requestedId
          : req.user.clientId;
        const company = await q.getOrCreateCompany(effectiveClientId, effectiveClientId);
        companyId = company.id;
      } else if (req.query.company) {
        const id = parseInt(req.query.company, 10);
        if (Number.isFinite(id) && id > 0) companyId = id;
      }
      const cidrs = await q.getExportCIDRs(companyId);
      const aggregated = aggregateCIDRs(cidrs);
      res.setHeader('Content-Type', 'text/plain; charset=utf-8');
      const fname = req.query.filename || 'white-list.txt';
      const disp  = req.query.view === '1' ? 'inline' : 'attachment';
      res.setHeader('Content-Disposition', `${disp}; filename="${fname}"`);
      res.send(aggregated.join('\n') + (aggregated.length ? '\n' : ''));
    } catch (e) {
      res.status(500).json({ error: e.message });
    }
  });

  // POST /api/v1/entries — создать запись
  router.post('/', json, async (req, res) => {
    const { value, comment } = req.body || {};
    if (!value) return res.status(400).json({ error: 'value required' });
    if (comment && comment.length > 255) return res.status(400).json({ error: 'Комментарий слишком длинный (максимум 255 символов)' });
    try {
      const company = await resolveCompany(req);
      const { entry, wasNormalized } = await q.createEntry(company.id, value, comment || '', req.user.email);
      res.status(201).json({ entry, wasNormalized });
    } catch (e) {
      if (e.status) return res.status(e.status).json({ error: e.message });
      handleQueryError(e, res);
    }
  });

  // PATCH /api/v1/entries/:id — обновить запись
  router.patch('/:id', json, async (req, res) => {
    const { value, comment } = req.body || {};
    if (!value) return res.status(400).json({ error: 'value required' });
    if (comment && comment.length > 255) return res.status(400).json({ error: 'Комментарий слишком длинный (максимум 255 символов)' });
    try {
      const company = await resolveCompany(req);
      const { entry, wasNormalized } = await q.updateEntry(req.params.id, company.id, value, comment ?? '', req.user.email);
      res.json({ entry, wasNormalized });
    } catch (e) {
      if (e.status) return res.status(e.status).json({ error: e.message });
      handleQueryError(e, res);
    }
  });

  // DELETE /api/v1/entries/:id — удалить запись
  router.delete('/:id', async (req, res) => {
    try {
      const company = await resolveCompany(req);
      await q.deleteEntry(req.params.id, company.id, req.user.email);
      res.status(204).send();
    } catch (e) {
      if (e.status) return res.status(e.status).json({ error: e.message });
      handleQueryError(e, res);
    }
  });

  return router;
}

module.exports = { createEntriesRouter };
