'use strict';

const reportesService = require('./reportesService');
const dashboardService = require('./dashboardCacheService');
const graficasService = require('./graficasService');
const { buildDecisionMetrics } = require('./advancedAnalysisMetrics');
const { localDateStr } = require('../utils/localDate');

const DAY_MS = 86400000;

function toDateOnly(date) {
  return localDateStr(date);
}

function addDays(date, days) {
  return new Date(date.getTime() + days * DAY_MS);
}

function parseDateOnly(value) {
  const text = String(value || '').trim();
  if (!/^\d{4}-\d{2}-\d{2}$/.test(text)) return null;
  const date = new Date(`${text}T00:00:00`);
  return Number.isNaN(date.getTime()) ? null : text;
}

function yearRange(year) {
  const y = Math.max(2000, Math.min(2100, Number(year) || new Date().getFullYear()));
  return { inicio: `${y}-01-01`, fin: `${y}-12-31`, anio: y };
}

function money(n) {
  return `$${Number(n || 0).toLocaleString('es-MX', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
}

function pct(n) {
  if (!Number.isFinite(Number(n))) return 'N/D';
  return `${Math.round(Number(n) * 100) / 100}%`;
}

function topRows(rows, labelKey, valueKey, limit = 10, qtyKey = null) {
  return (rows || []).slice(0, limit).map((row, idx) => {
    const label = row[labelKey] || row.descripcion || row.producto || row.mesero || row.forma_pago || `Fila ${idx + 1}`;
    const value = money(row[valueKey] || row.total || row.venta || row.total_venta || 0);
    const qty = qtyKey ? `, ${Number(row[qtyKey] || 0)} uds/tickets` : '';
    return `- ${label}: ${value}${qty}`;
  }).join('\n') || '- Sin datos';
}

function summarizePeriod(name, data) {
  const total = data?.totales || {};
  const op = data?.resumenOperativo || {};
  const cancel = data?.cancelaciones?.resumen || {};
  const ventas = data?.ventasPorDia || [];
  const promedioDia = ventas.length ? ventas.reduce((sum, row) => sum + Number(row.venta || 0), 0) / ventas.length : 0;
  const mejorDia = ventas.reduce((best, row) => Number(row.venta || 0) > Number(best.venta || 0) ? row : best, { venta: 0 });
  const peorDia = ventas.filter(row => Number(row.venta || 0) > 0)
    .reduce((worst, row) => Number(row.venta || 0) < Number(worst.venta || Infinity) ? row : worst, { venta: Infinity });

  return `
== ${name} ==
Periodo: ${data?.periodo?.inicio || 'N/D'} a ${data?.periodo?.fin || 'N/D'} (${data?.periodo?.dias || 0} dias)
Venta total: ${money(total.venta_total)}
Tickets: ${Number(total.tickets || 0)}
Ticket promedio: ${money(Number(total.tickets || 0) ? Number(total.venta_total || 0) / Number(total.tickets || 1) : 0)}
Promedio diario: ${money(promedioDia)}
Descuentos: ${money(total.descuentos || op.descuentos)}
Cortesias: ${money(total.cortesias || op.cortesias)}
Propinas: ${money(op.propinas)}
Personas: ${Number(op.personas || 0)}
Articulos: ${Number(op.articulos || 0)}
Mejor dia: ${mejorDia.fecha || 'N/D'} ${money(mejorDia.venta)}
Peor dia con venta: ${peorDia.fecha || 'N/D'} ${money(peorDia.venta === Infinity ? 0 : peorDia.venta)}
Cancelaciones: ${Number(cancel.cuentas_canceladas || 0)} cuentas / ${money(cancel.importe_cuentas)}

Top productos:
${topRows(data?.top_productos, 'producto', 'total_venta', 12, 'cantidad_vendida')}

Ventas por hora:
${(data?.ventasHora || []).map(row => `- ${String(row.hora).padStart(2, '0')}:00: ${money(row.venta)} (${Number(row.tickets || 0)} tickets)`).join('\n') || '- Sin datos'}

Canales:
${topRows(data?.ventasServicio, 'servicio', 'total', 8, 'tickets')}

Formas de pago:
${topRows(data?.formasPago, 'forma_pago', 'total', 8, 'tickets')}

Meseros:
${topRows(data?.meseros, 'mesero', 'venta', 8, 'tickets')}
`.trim();
}

function compare(current, previous) {
  const cv = Number(current?.totales?.venta_total || 0);
  const pv = Number(previous?.totales?.venta_total || 0);
  const ct = Number(current?.totales?.tickets || 0);
  const pt = Number(previous?.totales?.tickets || 0);
  const deltaVenta = pv ? ((cv - pv) / pv) * 100 : null;
  const deltaTickets = pt ? ((ct - pt) / pt) * 100 : null;
  const cTicket = ct ? cv / ct : 0;
  const pTicket = pt ? pv / pt : 0;
  const deltaTicketProm = pTicket ? ((cTicket - pTicket) / pTicket) * 100 : null;

  return `
COMPARATIVO CONTRA PERIODO ANTERIOR
- Venta: ${money(cv)} vs ${money(pv)} (${pct(deltaVenta)})
- Tickets: ${ct} vs ${pt} (${pct(deltaTickets)})
- Ticket promedio: ${money(cTicket)} vs ${money(pTicket)} (${pct(deltaTicketProm)})
`.trim();
}

async function buildAdvancedContext(options = {}) {
  const today = toDateOnly(new Date());
  const actualYear = yearRange(options.anioActual);
  const previousYear = yearRange(options.anioAnterior || (actualYear.anio - 1));
  const inicio = parseDateOnly(options.inicio) || today;
  const fin = parseDateOnly(options.fin) || inicio;
  const days = Math.max(1, Math.round((new Date(`${fin}T00:00:00`) - new Date(`${inicio}T00:00:00`)) / DAY_MS) + 1);
  const prevFinDefault = toDateOnly(addDays(new Date(`${inicio}T00:00:00`), -1));
  const prevInicioDefault = toDateOnly(addDays(new Date(`${prevFinDefault}T00:00:00`), -(days - 1)));
  const prevInicio = parseDateOnly(options.prevInicio) || prevInicioDefault;
  const prevFin = parseDateOnly(options.prevFin) || prevFinDefault;
  const idgrupo = String(options.idgrupo || '').replace(/[^a-zA-Z0-9_-]/g, '');
  const categoria = String(options.categoria || '').trim();
  const limite = Math.max(5, Math.min(50, Number(options.limite || 10)));

  const [historico, anterior, hoy, dashboard, topCantidad, topImporte, comparativoProductos] = await Promise.all([
    reportesService.getReporteData(inicio, fin),
    reportesService.getReporteData(prevInicio, prevFin),
    reportesService.getReporteData(fin, fin),
    dashboardService.getSnapshotCompleto?.().catch(() => null),
    graficasService.getTopProductos({ anio: actualYear.anio, limite, criterio: 'cantidad', orden: 'mas', idgrupo: idgrupo || null }).catch(() => []),
    graficasService.getTopProductos({ anio: actualYear.anio, limite, criterio: 'importe', orden: 'mas', idgrupo: idgrupo || null }).catch(() => []),
    graficasService.getComparativoProductos({ anioActual: actualYear.anio, anioAnterior: previousYear.anio, limite, idgrupo: idgrupo || null }).catch(() => []),
  ]);

  const currentSnapshot = options.contexto
    ? `\nSNAPSHOT ENVIADO POR EL FRONTEND\n${String(options.contexto).slice(0, 12000)}\n`
    : '';

  const dashboardText = dashboard
    ? `\nSNAPSHOT OPERATIVO EN VIVO\n${JSON.stringify(dashboard).slice(0, 12000)}\n`
    : '';
  const decisionMetrics = buildDecisionMetrics(historico, anterior, days);

  const texto = `
ANALISIS AVANZADO ARKHON
Fuente: SoftRestaurant SQL Server, reportes historicos y snapshot operativo local.
Fecha local: ${new Date().toLocaleString('es-MX')}
Periodo solicitado: ${inicio} a ${fin}
Comparativo solicitado: ${prevInicio} a ${prevFin}
Categoria seleccionada: ${categoria || idgrupo || 'Todas'}
Regla critica: analiza el periodo solicitado desde ARKHON. Si el snapshot de hoy aparece en cero pero el periodo tiene ventas, no concluyas "negocio sin actividad"; diagnostica filtro temporal, turno aun no cerrado, sincronizacion o datos en tempcheques.
Regla de formato: no uses emojis ni pictogramas. Usa texto plano, numeros y listas markdown.

${currentSnapshot}
${dashboardText}

${summarizePeriod(`HISTORICO ${days} DIAS`, historico)}

${summarizePeriod('HOY', hoy)}

${summarizePeriod(`PERIODO ANTERIOR ${days} DIAS`, anterior)}

${compare(historico, anterior)}

KPIS CALCULADOS POR ARKHON (FUENTE DETERMINISTA; NO RECALCULAR)
${JSON.stringify(decisionMetrics, null, 2)}

DATOS DE GRAFICAS ARKHON PARA EL PERIODO SELECCIONADO
Top por cantidad${categoria ? ` (${categoria})` : ''}:
${topRows(topCantidad, 'producto', 'total_importe', limite, 'total_cantidad')}

Top por importe${categoria ? ` (${categoria})` : ''}:
${topRows(topImporte, 'producto', 'total_importe', limite, 'total_cantidad')}

Comparativo de productos ${actualYear.anio} vs ${previousYear.anio}${categoria ? ` (${categoria})` : ''}:
${(comparativoProductos || []).map(row => `- ${row.producto}: ${money(row.importe_actual)} actual vs ${money(row.importe_anterior)} anterior; ${Number(row.cantidad_actual || 0)} uds vs ${Number(row.cantidad_anterior || 0)} uds`).join('\n') || '- Sin datos'}

INSTRUCCIONES DE ANALISIS
- Usa el periodo solicitado para detectar patrones realistas, no solo el momento actual.
- Separa problemas de conectividad/datos de problemas reales de operacion.
- Prioriza acciones para hoy y decisiones de inventario/productos.
- Menciona productos o canales por nombre cuando existan en datos.
- Si faltan datos, indica exactamente que fuente o tabla parece faltar.
- Distingue siempre entre HECHO observado, CALCULO ARKHON e INFERENCIA.
- No presentes causalidad cuando solo exista correlacion.
- Asigna nivel de confianza alto, medio o bajo a cada hallazgo principal.
- Toda accion debe incluir responsable sugerido, horizonte y KPI de verificacion.
- No uses emojis.
`.trim();

  return {
    texto,
    meta: {
      days,
      inicio,
      fin,
      prevInicio,
      prevFin,
      anioActual: actualYear.anio,
      anioAnterior: previousYear.anio,
      idgrupo: idgrupo || null,
      categoria: categoria || null,
      venta_historica: historico?.totales?.venta_total || 0,
      tickets_historicos: historico?.totales?.tickets || 0,
      venta_hoy: hoy?.totales?.venta_total || 0,
      tickets_hoy: hoy?.totales?.tickets || 0,
      kpis: decisionMetrics,
    },
  };
}

module.exports = { buildAdvancedContext };
