const { Router } = require('express');
const XLSX = require('xlsx');
const { pool } = require('../db/pool');
const { requireAuth } = require('../middlewares/auth.middleware');
const env = require('../config/env');
const {
  clampInt,
  parseListParam,
  getInvimaCatalog,
  getInvimaCatalogForExport,
  getInvimaCatalogForExportChunk,
  listInvimaCategories,
  listInvimaFilterOptions,
  listInvimaDatasets,
  getInvimaSyncStats,
  toCsv
} = require('../../invima/service');
const {
  getInvimaSyncJob,
  startInvimaSyncJob
} = require('../../invima/sync-job-manager');

const router = Router();

router.use(requireAuth);

router.get('/datasets', (_req, res) => {
  res.json({ items: listInvimaDatasets() });
});

router.get('/categorias', async (_req, res, next) => {
  try {
    const items = await listInvimaCategories(pool);
    res.json({ items });
  } catch (error) {
    next(error);
  }
});

router.get('/filtros', async (_req, res, next) => {
  try {
    const items = await listInvimaFilterOptions(pool);
    res.json(items);
  } catch (error) {
    next(error);
  }
});

router.get('/sync/stats', async (req, res, next) => {
  try {
    const datasets = parseListParam(req.query.datasets);
    const stats = await getInvimaSyncStats(pool, { datasets });
    res.json(stats);
  } catch (error) {
    next(error);
  }
});

router.get('/sync/job', (_req, res) => {
  res.json({ ok: true, job: getInvimaSyncJob() });
});

router.post('/sync', async (req, res, next) => {
  try {
    const datasets = parseListParam(req.body?.datasets ?? req.query.datasets);
    const pageSize = clampInt(req.body?.pageSize ?? req.query.pageSize, 1000, 100, 5000);
    const maxPagesRaw = req.body?.maxPages ?? req.query.maxPages;
    const maxPages =
      maxPagesRaw === undefined || maxPagesRaw === null || String(maxPagesRaw).trim() === ''
        ? null
        : clampInt(maxPagesRaw, 1, 1, 50000);

    const result = startInvimaSyncJob(pool, {
      datasets,
      pageSize,
      maxPages,
      concurrency: clampInt(req.body?.concurrency ?? req.query.concurrency, 3, 1, 8),
      fetchRetries: clampInt(req.body?.fetchRetries ?? req.query.fetchRetries, 4, 0, 8),
      fetchTimeoutMs: clampInt(req.body?.fetchTimeoutMs ?? req.query.fetchTimeoutMs, 35000, 4000, 120000),
      where: req.body?.where ?? req.query.where,
      select: req.body?.select ?? req.query.select,
      order: req.body?.order ?? req.query.order,
      appToken: env.SOCRATA_APP_TOKEN
    });

    res.status(result.alreadyRunning ? 200 : 202).json({
      ok: true,
      alreadyRunning: result.alreadyRunning,
      job: result.job
    });
  } catch (error) {
    next(error);
  }
});

router.get('/catalogo', async (req, res, next) => {
  try {
    const result = await getInvimaCatalog(pool, req.query);
    res.json(result);
  } catch (error) {
    next(error);
  }
});

router.get('/catalogo/export', async (req, res, next) => {
  try {
    const format = String(req.query.format || 'csv').toLowerCase();
    const now = new Date().toISOString().replace(/[:.]/g, '-');

    if (format === 'csv') {
      const exportLimit = clampInt(req.query.exportLimit, 50000, 1, 1_000_000);
      const chunkLimit = clampInt(req.query.chunkLimit, 5000, 100, 20000);
      let exported = 0;
      let offset = 0;
      let wroteHeader = false;

      res.setHeader('Content-Type', 'text/csv; charset=utf-8');
      res.setHeader('Content-Disposition', `attachment; filename=\"invima_catalogo_${now}.csv\"`);

      while (exported < exportLimit) {
        const remaining = exportLimit - exported;
        const rows = await getInvimaCatalogForExportChunk(pool, {
          ...req.query,
          chunkLimit: Math.min(chunkLimit, remaining),
          chunkOffset: offset
        });
        if (!rows.length) break;

        const csv = toCsv(rows);
        if (!wroteHeader) {
          res.write(csv);
          wroteHeader = true;
        } else {
          const firstBreak = csv.indexOf('\n');
          if (firstBreak >= 0 && firstBreak < csv.length - 1) {
            res.write(`\n${csv.slice(firstBreak + 1)}`);
          }
        }

        exported += rows.length;
        offset += rows.length;
        if (rows.length < chunkLimit) break;
      }

      res.end();
      return;
    }

    if (format === 'xlsx') {
      const rows = await getInvimaCatalogForExport(pool, {
        ...req.query,
        exportLimit: clampInt(req.query.exportLimit, 50000, 1, 200000)
      });
      const workbook = XLSX.utils.book_new();
      const worksheet = XLSX.utils.json_to_sheet(rows);
      XLSX.utils.book_append_sheet(workbook, worksheet, 'INVIMA');
      const buffer = XLSX.write(workbook, { type: 'buffer', bookType: 'xlsx' });
      res.setHeader(
        'Content-Type',
        'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
      );
      res.setHeader('Content-Disposition', `attachment; filename=\"invima_catalogo_${now}.xlsx\"`);
      res.send(buffer);
      return;
    }

    const rows = await getInvimaCatalogForExport(pool, req.query);
    const csv = toCsv(rows);
    res.setHeader('Content-Type', 'text/csv; charset=utf-8');
    res.setHeader('Content-Disposition', `attachment; filename=\"invima_catalogo_${now}.csv\"`);
    res.send(csv);
  } catch (error) {
    next(error);
  }
});

module.exports = router;
