'use strict';

const crypto = require('crypto');
const logger = require('../utils/logger');
const { getPool } = require('../db');
const openTableSessions = require('./mssqlExtractors/openTableSessionsExtractor');
const liveSalesSummary = require('./mssqlExtractors/liveSalesSummaryExtractor');
const liveServiceAreas = require('./mssqlExtractors/liveServiceAreasExtractor');
const { sendLiveSnapshot } = require('./syncClient');

function stablePayload(rows) {
  return (rows || []).map((row) => row.payload || row).map((row) => ({
    external_id: row.external_id,
    foliocuenta: row.foliocuenta,
    mesa: row.mesa,
    nombre_mesero: row.nombre_mesero,
    area_codigo: row.area_codigo,
    area_nombre: row.area_nombre,
    area_tipo: row.area_tipo,
    area_estado: row.area_estado,
    total: row.total,
    subtotal: row.subtotal,
    minutos_abierta: row.minutos_abierta,
    comandas: row.comandas,
    comensales: row.comensales,
    status: row.status,
    productos: row.productos || [],
  }));
}

function summarizeMesas(mesas) {
  return (mesas || []).reduce((summary, mesa) => {
    summary.mesas_abiertas += 1;
    summary.venta_en_curso += Number(mesa.total || 0);
    summary.comensales_en_curso += Number(mesa.comensales || 0);
    summary.partidas_en_curso += Array.isArray(mesa.productos) ? mesa.productos.length : 0;
    return summary;
  }, { mesas_abiertas: 0, venta_en_curso: 0, comensales_en_curso: 0, partidas_en_curso: 0 });
}

function startLiveTablesScheduler(config) {
  let running = false;
  let lastHash = '';
  let lastSentAt = 0;
  let cachedServiceAreas = [];
  let lastServiceAreasAt = 0;
  // El flujo de mesas es independiente de la sincronizacion historica. Dos
  // segundos deja margen para SQL + red + navegador y mantiene el objetivo
  // extremo a extremo por debajo de cinco segundos.
  const intervalMs = Math.max(1000, Number(process.env.ARKHON_LIVE_TABLES_INTERVAL_MS || 2000));
  const keepaliveMs = Math.max(10000, Number(process.env.ARKHON_LIVE_TABLES_KEEPALIVE_MS || 15000));

  async function tick() {
    if (running) return;
    running = true;
    try {
      const pool = await getPool();
      const refreshServiceAreas = Date.now() - lastServiceAreasAt >= 10000;
      const [rows, resumen, serviceAreas] = await Promise.all([
        openTableSessions.extract(pool, null, 500),
        liveSalesSummary.extract(pool),
        refreshServiceAreas
          ? liveServiceAreas.extract(pool).catch((error) => {
            logger.warn({ event: 'agent_live_service_areas_failed', error: error.message });
            return cachedServiceAreas;
          })
          : Promise.resolve(cachedServiceAreas),
      ]);
      if (refreshServiceAreas) {
        cachedServiceAreas = serviceAreas;
        lastServiceAreasAt = Date.now();
      }
      const mesas = stablePayload(rows);
      const snapshotHash = crypto.createHash('sha256').update(JSON.stringify({ mesas, resumen, ventas_servicio: serviceAreas })).digest('hex');
      if (snapshotHash === lastHash && Date.now() - lastSentAt < keepaliveMs) return;
      const generatedAt = new Date().toISOString();
      const liveTablesSummary = summarizeMesas(mesas);
      await sendLiveSnapshot(config, {
        snapshot_hash: snapshotHash,
        source_generated_at: generatedAt,
        partial: true,
        payload: { mesas, resumen, ventas_servicio: serviceAreas, live_tables_summary: liveTablesSummary, _live_tables_generated_at: generatedAt },
      });
      lastHash = snapshotHash;
      lastSentAt = Date.now();
    } catch (err) {
      logger.warn({ event: 'agent_live_tables_failed', error: err.message });
    } finally {
      running = false;
    }
  }

  tick();
  const timer = setInterval(tick, intervalMs);
  timer.unref?.();
  return timer;
}

module.exports = { startLiveTablesScheduler, stablePayload, summarizeMesas };
