'use strict';
// ═══════════════════════════════════════════════════════════════════════════════
// ARKHON — Servicio de Notificaciones WhatsApp (Meta Cloud API)
// Envía alertas automáticas al dueño del restaurante vía WhatsApp Business API:
//   1. Resumen al cierre de turno
//   2. Alerta cuando se alcanza la meta de ventas
//   3. Reporte diario automático
//   4. Alerta de productos sin movimiento
//   5. Alerta de cuentas canceladas
//   6. Alerta de productos cancelados
//   7. Alerta de retiros de caja
//   8. Alerta de depósitos en efectivo
//
// Configuración requerida en .env:
//   META_WA_TOKEN        = Token de acceso permanente (Meta Business → System User)
//   META_WA_PHONE_ID     = Phone Number ID del número de envío (Meta Developer Console)
//   WHATSAPP_DESTINATARIOS = Números destino separados por coma (+52XXXXXXXXXX)
//   WHATSAPP_ENABLED     = true
// ═══════════════════════════════════════════════════════════════════════════════

const https  = require('https');
const logger  = require('../utils/logger');
const { db }  = require('../utils/dbName');
const { getPool } = require('../db');
const { localDateStr } = require('../utils/localDate');

// ── Configuración ─────────────────────────────────────────────────────────────
function getConfig() {
  const token = process.env.WHATSAPP_ACCESS_TOKEN || process.env.META_WA_TOKEN || '';
  const phoneId = process.env.WHATSAPP_PHONE_NUMBER_ID || process.env.META_WA_PHONE_ID || '';
  return {
    token,
    phoneId,
    verifyToken: process.env.WHATSAPP_VERIFY_TOKEN || process.env.META_WA_VERIFY_TOKEN || '',
    toNumbers:   (process.env.WHATSAPP_DESTINATARIOS || '').split(',').map(n => n.trim()).filter(Boolean),
    enabled:     process.env.WHATSAPP_ENABLED === 'true',
    metaDiaria:  parseFloat(process.env.META_DIARIA) || 0,
  };
}

function isConfigured() {
  const c = getConfig();
  return c.enabled && !!c.token && !!c.phoneId && c.toNumbers.length > 0;
}

function validateConfig() {
  const c = getConfig();
  const missing = [];
  if (!c.token) missing.push('WHATSAPP_ACCESS_TOKEN');
  if (!c.phoneId) missing.push('WHATSAPP_PHONE_NUMBER_ID');
  if (!c.toNumbers.length) missing.push('WHATSAPP_DESTINATARIOS');
  return {
    ok: missing.length === 0,
    enabled: c.enabled,
    configured: c.enabled && missing.length === 0,
    missing,
  };
}

function normalizePhone(value) {
  return String(value || '')
    .replace(/^whatsapp:/i, '')
    .replace(/[^\d+]/g, '')
    .replace(/^\+/, '');
}

// ── Enviar mensaje de texto via Meta Cloud API ────────────────────────────────
// Docs: https://developers.facebook.com/docs/whatsapp/cloud-api/messages/text-messages
async function enviarWhatsApp(mensaje, destinatario) {
  const c = getConfig();
  if (!c.token || !c.phoneId) {
    logger.warn('[WhatsApp] Meta API no configurada — mensaje no enviado');
    return { ok: false, error: 'Meta API no configurada' };
  }

  // Normalizar número: quitar prefijo whatsapp: si viene del config anterior
  const to = normalizePhone(destinatario);

  const payload = JSON.stringify({
    messaging_product: 'whatsapp',
    recipient_type:    'individual',
    to,
    type: 'text',
    text: { preview_url: false, body: mensaje },
  });

  return new Promise((resolve) => {
    const options = {
      hostname: 'graph.facebook.com',
      path:     `/v20.0/${c.phoneId}/messages`,
      method:   'POST',
      headers: {
        'Authorization': `Bearer ${c.token}`,
        'Content-Type':  'application/json',
        'Content-Length': Buffer.byteLength(payload),
      },
    };

    const req = https.request(options, (res) => {
      let data = '';
      res.on('data', chunk => data += chunk);
      res.on('end', () => {
        try {
          const json = JSON.parse(data);
          // Meta responde con messages[0].id cuando es exitoso
          const msgId = json?.messages?.[0]?.id;
          if (msgId) {
            logger.info(`[WhatsApp] ✅ Enviado a ${to} (id: ${msgId})`);
            resolve({ ok: true, messageId: msgId });
          } else {
            const errMsg = json?.error?.message || JSON.stringify(json);
            logger.error(`[WhatsApp] ❌ Error Meta API: ${errMsg}`);
            resolve({ ok: false, error: errMsg });
          }
        } catch (e) {
          logger.error(`[WhatsApp] ❌ Parse error: ${e.message}`);
          resolve({ ok: false, error: e.message });
        }
      });
    });

    req.on('error', (e) => {
      logger.error(`[WhatsApp] ❌ Network error: ${e.message}`);
      resolve({ ok: false, error: e.message });
    });

    req.write(payload);
    req.end();
  });
}

async function sendTextMessage(to, text) {
  return enviarWhatsApp(text, to);
}

async function sendTemplateMessage(to, templateName, languageCode = 'es_MX', components = []) {
  const c = getConfig();
  if (!c.token || !c.phoneId) {
    logger.warn('[WhatsApp] Meta API no configurada - template no enviado');
    return { ok: false, error: 'Meta API no configurada' };
  }

  const payload = JSON.stringify({
    messaging_product: 'whatsapp',
    recipient_type: 'individual',
    to: normalizePhone(to),
    type: 'template',
    template: {
      name: templateName,
      language: { code: languageCode },
      components,
    },
  });

  return new Promise((resolve) => {
    const options = {
      hostname: 'graph.facebook.com',
      path: `/v20.0/${c.phoneId}/messages`,
      method: 'POST',
      headers: {
        Authorization: `Bearer ${c.token}`,
        'Content-Type': 'application/json',
        'Content-Length': Buffer.byteLength(payload),
      },
    };
    const req = https.request(options, (res) => {
      let data = '';
      res.on('data', chunk => data += chunk);
      res.on('end', () => {
        try {
          const json = JSON.parse(data);
          const msgId = json?.messages?.[0]?.id;
          resolve(msgId ? { ok: true, messageId: msgId } : { ok: false, error: json?.error?.message || JSON.stringify(json) });
        } catch (e) {
          resolve({ ok: false, error: e.message });
        }
      });
    });
    req.on('error', e => resolve({ ok: false, error: e.message }));
    req.write(payload);
    req.end();
  });
}

// Enviar a todos los destinatarios configurados
async function enviarATodos(mensaje) {
  const c = getConfig();
  const resultados = [];
  for (const num of c.toNumbers) {
    const r = await enviarWhatsApp(mensaje, num);
    resultados.push({ numero: num, ...r });
  }
  return resultados;
}

// ── Rate limiter — evitar spam en notificaciones automáticas ──────────────────
const _lastSent = {};
function canSend(tipo, cooldownMs = 5 * 60 * 1000) {
  const now = Date.now();
  if (_lastSent[tipo] && (now - _lastSent[tipo]) < cooldownMs) return false;
  _lastSent[tipo] = now;
  return true;
}

// ── 1. Resumen de cierre de turno ─────────────────────────────────────────────
async function notificarCierreTurno(idturno) {
  if (!isConfigured()) return;
  if (!canSend('cierreTurno_' + idturno, 10 * 60 * 1000)) return;
  try {
    const pool = await getPool();
    const r = await pool.request().query(`
      SELECT t.idturno, t.apertura, t.cierre,
        COUNT(DISTINCT c.folio)    AS tickets,
        ROUND(ISNULL(SUM(c.total),0),2) AS venta_total,
        COUNT(DISTINCT c.idmesero) AS meseros
      FROM ${db()}turnos t
      LEFT JOIN ${db()}cheques c ON c.idturno = t.idturno AND c.cancelado=0 AND c.pagado=1
      WHERE t.idturno = ${parseInt(idturno)}
      GROUP BY t.idturno, t.apertura, t.cierre
    `);
    if (!r.recordset.length) return;
    const t = r.recordset[0];
    const msg = `🔔 *ARKHON — Cierre de Turno*\n\n` +
      `📅 Turno: #${t.idturno}\n` +
      `💰 Venta: $${(t.venta_total||0).toLocaleString('es-MX',{minimumFractionDigits:2})}\n` +
      `🎫 Tickets: ${t.tickets||0}\n` +
      `👥 Meseros: ${t.meseros||0}\n` +
      `🕐 ${t.apertura ? new Date(t.apertura).toLocaleTimeString('es-MX') : '—'} → ${t.cierre ? new Date(t.cierre).toLocaleTimeString('es-MX') : 'Abierto'}`;
    await enviarATodos(msg);
  } catch(e) {
    logger.error(`[WhatsApp] Error notificarCierreTurno: ${e.message}`);
  }
}

// ── 2. Alerta de meta alcanzada ───────────────────────────────────────────────
let _metaNotificada = false;
async function verificarMeta() {
  if (!isConfigured()) return;
  const c = getConfig();
  if (!c.metaDiaria || c.metaDiaria <= 0) return;
  if (_metaNotificada) return;
  try {
    const pool = await getPool();
    const hoy = localDateStr();
    const r = await pool.request().query(`
      SELECT ROUND(ISNULL(SUM(total),0),2) AS venta
      FROM ${db()}cheques
      WHERE CAST(fecha AS DATE) = '${hoy}' AND cancelado=0 AND pagado=1
    `);
    const venta = r.recordset[0]?.venta || 0;
    if (venta >= c.metaDiaria) {
      _metaNotificada = true;
      const pct = Math.round(venta / c.metaDiaria * 100);
      const msg = `🎯 *ARKHON — ¡Meta Alcanzada!*\n\n` +
        `💰 Venta del día: $${venta.toLocaleString('es-MX',{minimumFractionDigits:2})}\n` +
        `🎯 Meta: $${c.metaDiaria.toLocaleString('es-MX',{minimumFractionDigits:2})}\n` +
        `📊 Progreso: ${pct}%\n` +
        `📅 ${hoy}`;
      await enviarATodos(msg);
    }
  } catch(e) {
    logger.error(`[WhatsApp] Error verificarMeta: ${e.message}`);
  }
}

function resetMeta() { _metaNotificada = false; }

// ── 3. Reporte diario automático ──────────────────────────────────────────────
async function reporteDiario() {
  if (!isConfigured()) return;
  try {
    const pool = await getPool();
    const hoy = localDateStr();

    const res = await pool.request().query(`
      SELECT COUNT(DISTINCT folio) AS tickets,
        ROUND(ISNULL(SUM(total),0),2) AS venta,
        COUNT(DISTINCT idmesero) AS meseros
      FROM ${db()}cheques
      WHERE CAST(fecha AS DATE) = '${hoy}' AND cancelado=0 AND pagado=1
    `);
    const r = res.recordset[0] || {};
    const ticketProm = r.tickets > 0 ? Math.round(r.venta / r.tickets * 100) / 100 : 0;

    const topRes = await pool.request().query(`
      SELECT TOP 5 LTRIM(RTRIM(p.descripcion)) AS producto,
        ROUND(SUM(cd.cantidad),0) AS qty, ROUND(SUM(cd.cantidad*cd.precio),2) AS venta
      FROM ${db()}cheqdet cd
      INNER JOIN ${db()}cheques c ON cd.foliodet=c.folio
      INNER JOIN ${db()}productos p ON cd.idproducto=p.idproducto
      WHERE CAST(c.fecha AS DATE)='${hoy}' AND c.cancelado=0 AND c.pagado=1 AND cd.modificador=0
      GROUP BY p.descripcion ORDER BY venta DESC
    `);

    let topList = '';
    topRes.recordset.forEach((p, i) => {
      topList += `  ${i+1}. ${p.producto}: ${p.qty} uds → $${p.venta.toLocaleString('es-MX',{minimumFractionDigits:2})}\n`;
    });

    const msg = `📊 *ARKHON — Reporte del Día*\n\n` +
      `📅 ${hoy}\n` +
      `💰 Venta total: $${(r.venta||0).toLocaleString('es-MX',{minimumFractionDigits:2})}\n` +
      `🎫 Tickets: ${r.tickets||0}\n` +
      `💵 Ticket promedio: $${ticketProm.toLocaleString('es-MX',{minimumFractionDigits:2})}\n` +
      `👥 Meseros activos: ${r.meseros||0}\n\n` +
      `🏆 *Top 5 Productos:*\n${topList || '  Sin datos'}`;

    await enviarATodos(msg);
  } catch(e) {
    logger.error(`[WhatsApp] Error reporteDiario: ${e.message}`);
  }
}

// ── 4. Alerta de productos sin movimiento ─────────────────────────────────────
async function alertaSinMovimiento() {
  if (!isConfigured()) return;
  try {
    const pool = await getPool();
    const hoy = localDateStr();

    const r = await pool.request().query(`
      SELECT TOP 10 LTRIM(RTRIM(p.descripcion)) AS producto,
        ISNULL(g.descripcion,'Sin grupo') AS grupo
      FROM ${db()}productos p
      LEFT JOIN ${db()}grupos g ON p.idgrupo=g.idgrupo
      LEFT JOIN ${db()}productosdetalle pd ON pd.idproducto=p.idproducto
      WHERE p.idproducto NOT IN (
        SELECT DISTINCT cd.idproducto FROM ${db()}cheqdet cd
        INNER JOIN ${db()}cheques c ON cd.foliodet=c.folio
        WHERE CAST(c.fecha AS DATE)='${hoy}' AND c.cancelado=0 AND c.pagado=1 AND cd.modificador=0
      ) AND ISNULL(pd.bloqueado,0)=0
      ORDER BY g.descripcion, p.descripcion
    `);

    if (!r.recordset.length) return;

    let lista = '';
    r.recordset.forEach((p, i) => {
      lista += `  ${i+1}. ${p.producto} (${p.grupo})\n`;
    });

    const msg = `⚠️ *ARKHON — Productos Sin Movimiento*\n\n` +
      `📅 ${hoy}\n` +
      `Los siguientes productos no se han vendido hoy:\n\n${lista}\n` +
      `Considera promociones o revisión de inventario.`;

    await enviarATodos(msg);
  } catch(e) {
    logger.error(`[WhatsApp] Error alertaSinMovimiento: ${e.message}`);
  }
}

// ── 5. Alerta de cuentas canceladas ──────────────────────────────────────────
async function alertaCancelaciones() {
  if (!isConfigured()) return;
  if (!canSend('cancelaciones')) return;
  try {
    const pool = await getPool();
    const hoy = localDateStr();
    const r = await pool.request().query(`
      SELECT c.folio, LTRIM(RTRIM(ISNULL(m.nombre, 'Sin mesero'))) AS mesero,
        ROUND(ISNULL(c.total,0),2) AS total, c.fecha
      FROM ${db()}cheques c
      LEFT JOIN ${db()}meseros m ON c.idmesero = m.idmesero
      WHERE CAST(c.fecha AS DATE) = '${hoy}' AND c.cancelado = 1
      ORDER BY c.fecha DESC
    `);
    if (!r.recordset.length) return;

    const totalCanc = r.recordset.reduce((s, c) => s + (c.total || 0), 0);
    let lista = '';
    r.recordset.forEach((c, i) => {
      lista += `  ${i+1}. Folio #${c.folio} — $${(c.total||0).toLocaleString('es-MX',{minimumFractionDigits:2})} (${c.mesero})\n`;
    });

    const msg = `🚫 *ARKHON — Cuentas Canceladas*\n\n` +
      `📅 ${hoy}\n` +
      `Se cancelaron ${r.recordset.length} cuenta(s) por un total de $${totalCanc.toLocaleString('es-MX',{minimumFractionDigits:2})}:\n\n${lista}`;
    await enviarATodos(msg);
  } catch(e) {
    logger.error(`[WhatsApp] Error alertaCancelaciones: ${e.message}`);
  }
}

// ── 6. Alerta de productos cancelados ────────────────────────────────────────
async function alertaProductosCancelados() {
  if (!isConfigured()) return;
  if (!canSend('productosCancelados')) return;
  try {
    const pool = await getPool();
    const hoy = localDateStr();
    const r = await pool.request().query(`
      SELECT TOP 15 LTRIM(RTRIM(p.descripcion)) AS producto,
        ROUND(SUM(cd.cantidad),0) AS cantidad,
        ROUND(SUM(cd.cantidad * cd.precio),2) AS total
      FROM ${db()}cheqdet cd
      INNER JOIN ${db()}cheques c ON cd.foliodet = c.folio
      INNER JOIN ${db()}productos p ON cd.idproducto = p.idproducto
      WHERE CAST(c.fecha AS DATE) = '${hoy}' AND cd.modificador IN (-1, 2)
      GROUP BY p.descripcion
      ORDER BY total DESC
    `);
    if (!r.recordset.length) return;

    const totalCanc = r.recordset.reduce((s, p) => s + (p.total || 0), 0);
    let lista = '';
    r.recordset.forEach((p, i) => {
      lista += `  ${i+1}. ${p.producto}: ${p.cantidad} uds → $${(p.total||0).toLocaleString('es-MX',{minimumFractionDigits:2})}\n`;
    });

    const msg = `❌ *ARKHON — Productos Cancelados*\n\n` +
      `📅 ${hoy}\n` +
      `Se cancelaron productos por $${totalCanc.toLocaleString('es-MX',{minimumFractionDigits:2})}:\n\n${lista}`;
    await enviarATodos(msg);
  } catch(e) {
    logger.error(`[WhatsApp] Error alertaProductosCancelados: ${e.message}`);
  }
}

// ── 7. Alerta de retiros de caja ──────────────────────────────────────────────
async function alertaRetiros() {
  if (!isConfigured()) return;
  if (!canSend('retiros')) return;
  try {
    const pool = await getPool();
    const hoy = localDateStr();
    const r = await pool.request().query(`
      SELECT ISNULL(d.concepto, 'Sin concepto') AS concepto,
        ROUND(ISNULL(d.importe,0),2) AS importe, d.fecha
      FROM ${db()}declaracioncajero d
      WHERE CAST(d.fecha AS DATE) = '${hoy}' AND d.importe > 0
      ORDER BY d.fecha DESC
    `);
    if (!r.recordset.length) return;

    const totalRet = r.recordset.reduce((s, d) => s + (d.importe || 0), 0);
    let lista = '';
    r.recordset.forEach((d, i) => {
      lista += `  ${i+1}. $${(d.importe||0).toLocaleString('es-MX',{minimumFractionDigits:2})} — ${d.concepto}\n`;
    });

    const msg = `💸 *ARKHON — Retiros de Caja*\n\n` +
      `📅 ${hoy}\n` +
      `${r.recordset.length} retiro(s) por $${totalRet.toLocaleString('es-MX',{minimumFractionDigits:2})}:\n\n${lista}`;
    await enviarATodos(msg);
  } catch(e) {
    logger.error(`[WhatsApp] Error alertaRetiros: ${e.message}`);
  }
}

// ── 8. Alerta de depósitos en efectivo ───────────────────────────────────────
async function alertaDepositos() {
  if (!isConfigured()) return;
  if (!canSend('depositos')) return;
  try {
    const pool = await getPool();
    const hoy = localDateStr();
    const r = await pool.request().query(`
      SELECT ISNULL(d.concepto, 'Sin concepto') AS concepto,
        ROUND(ABS(ISNULL(d.importe,0)),2) AS importe, d.fecha
      FROM ${db()}declaracioncajero d
      WHERE CAST(d.fecha AS DATE) = '${hoy}' AND d.importe < 0
      ORDER BY d.fecha DESC
    `);
    if (!r.recordset.length) return;

    const totalDep = r.recordset.reduce((s, d) => s + (d.importe || 0), 0);
    let lista = '';
    r.recordset.forEach((d, i) => {
      lista += `  ${i+1}. $${(d.importe||0).toLocaleString('es-MX',{minimumFractionDigits:2})} — ${d.concepto}\n`;
    });

    const msg = `💵 *ARKHON — Depósitos en Efectivo*\n\n` +
      `📅 ${hoy}\n` +
      `${r.recordset.length} depósito(s) por $${totalDep.toLocaleString('es-MX',{minimumFractionDigits:2})}:\n\n${lista}`;
    await enviarATodos(msg);
  } catch(e) {
    logger.error(`[WhatsApp] Error alertaDepositos: ${e.message}`);
  }
}

// ── Mensaje de prueba ─────────────────────────────────────────────────────────
async function enviarPrueba(numero) {
  const msg = `✅ *ARKHON Monitor — Conexión exitosa*\n\n` +
    `Las notificaciones de WhatsApp están funcionando correctamente (Meta Cloud API).\n` +
    `📅 ${localDateStr()} ${new Date().toLocaleTimeString('es-MX')}`;
  if (numero) return enviarWhatsApp(msg, numero);
  return enviarATodos(msg);
}

// ── Webhook de verificación Meta (GET) ───────────────────────────────────────
// Meta llama a este endpoint para verificar el webhook durante la configuración.
// Retorna el hub.challenge si el token coincide con META_WA_VERIFY_TOKEN.
function verificarWebhook(req, res) {
  const mode      = req.query['hub.mode'];
  const token     = req.query['hub.verify_token'];
  const challenge = req.query['hub.challenge'];
  const expected  = getConfig().verifyToken;

  if (mode === 'subscribe' && token === expected) {
    logger.info('[WhatsApp] Webhook verificado por Meta ✅');
    return res.status(200).send(challenge);
  }
  logger.warn('[WhatsApp] Verificación de webhook fallida');
  return res.sendStatus(403);
}

// ── Scheduler ────────────────────────────────────────────────────────────────
let _intervals = [];

function iniciarScheduler() {
  detenerScheduler();
  if (!isConfigured()) {
    logger.info('[WhatsApp] No configurado — scheduler no iniciado');
    return;
  }

  logger.info(`[WhatsApp] ✅ Scheduler iniciado (Meta API) — ${getConfig().toNumbers.length} destinatario(s)`);

  // Verificar meta cada 5 minutos
  _intervals.push(setInterval(verificarMeta, 5 * 60 * 1000));

  // Reset meta a medianoche
  _intervals.push(setInterval(() => {
    const now = new Date();
    if (now.getHours() === 0 && now.getMinutes() < 2) resetMeta();
  }, 60 * 1000));

  // Reporte diario a las 11:00 PM
  _intervals.push(setInterval(async () => {
    const now = new Date();
    if (now.getHours() === 23 && now.getMinutes() === 0) {
      await reporteDiario();
      await alertaSinMovimiento();
    }
  }, 60 * 1000));
}

function detenerScheduler() {
  _intervals.forEach(i => clearInterval(i));
  _intervals = [];
}

module.exports = {
  getConfig,
  isConfigured,
  validateConfig,
  normalizePhone,
  enviarWhatsApp,
  sendTextMessage,
  sendTemplateMessage,
  enviarATodos,
  enviarPrueba,
  verificarWebhook,
  notificarCierreTurno,
  verificarMeta,
  reporteDiario,
  alertaSinMovimiento,
  alertaCancelaciones,
  alertaProductosCancelados,
  alertaRetiros,
  alertaDepositos,
  iniciarScheduler,
  detenerScheduler,
};
