<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1.0"/>
<title>Reporte de Ventas — ARKHON</title>
<link rel="preconnect" href="https://fonts.googleapis.com"/>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet"/>
<style>
:root{
  --bg:#f7f8fc;--surface:#fff;--border:#eaecf4;
  --text:#111827;--text-2:#4b5563;--text-3:#9ca3af;
  --orange:#f97316;--orange-lt:rgba(249,115,22,.10);
  --green:#10b981;--green-lt:rgba(16,185,129,.10);
  --blue:#2563eb;--blue-lt:rgba(37,99,235,.10);
  --red:#ef4444;--red-lt:rgba(239,68,68,.10);
  --amber:#f59e0b;--amber-lt:rgba(245,158,11,.10);
  --shadow-sm:0 1px 3px rgba(17,24,39,.06);--shadow:0 2px 8px rgba(17,24,39,.08);
  --r:10px;
}
*{margin:0;padding:0;box-sizing:border-box;}
html,body{font-family:'Plus Jakarta Sans',sans-serif;background:var(--bg);color:var(--text);min-height:100vh;font-size:13px;-webkit-font-smoothing:antialiased;}
button,input,select{font-family:'Plus Jakarta Sans',sans-serif;}
::-webkit-scrollbar{width:4px;height:4px;}
::-webkit-scrollbar-thumb{background:#d1d5db;border-radius:8px;}
@keyframes spin{to{transform:rotate(360deg);}}
@keyframes fadeUp{from{opacity:0;transform:translateY(8px);}to{opacity:1;transform:translateY(0);}}
.topbar{background:var(--surface);border-bottom:1px solid var(--border);height:58px;padding:0 20px;display:flex;align-items:center;gap:12px;box-shadow:var(--shadow-sm);position:sticky;top:0;z-index:20;}
.topbar-icon{width:34px;height:34px;border-radius:9px;flex-shrink:0;background:var(--orange);display:flex;align-items:center;justify-content:center;box-shadow:0 3px 10px rgba(249,115,22,.28);}
.topbar-icon svg{width:16px;height:16px;stroke:#fff;stroke-width:2.2;fill:none;}
.topbar h1{font-size:15px;font-weight:800;color:var(--text);letter-spacing:-.3px;flex:1;}
.container{max-width:1060px;margin:0 auto;padding:18px 18px 40px;}
.filters-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--r);box-shadow:var(--shadow-sm);padding:14px 18px;margin-bottom:14px;display:flex;align-items:flex-end;gap:12px;flex-wrap:wrap;}
.fg{display:flex;flex-direction:column;gap:3px;}
.fl{font-size:9px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--text-3);}
input[type=date]{padding:7px 10px;border:1px solid var(--border);border-radius:8px;font-size:12px;font-weight:600;color:var(--text);outline:none;transition:.15s;background:var(--surface);}
input[type=date]:focus{border-color:var(--orange);}
.btn-primary{display:flex;align-items:center;gap:6px;padding:8px 18px;background:var(--orange);color:#fff;border:none;border-radius:8px;font-size:12px;font-weight:700;cursor:pointer;box-shadow:0 2px 8px rgba(249,115,22,.28);transition:.15s;}
.btn-primary:hover{transform:translateY(-1px);}
.btn-primary svg{width:13px;height:13px;stroke:#fff;stroke-width:2.2;fill:none;}
.btn-secondary{display:flex;align-items:center;gap:6px;padding:8px 14px;background:var(--surface);color:var(--text);border:1px solid var(--border);border-radius:8px;font-size:12px;font-weight:700;cursor:pointer;transition:.15s;}
.btn-secondary:hover{border-color:#d7ddea;background:#fbfcff;}
.btn-secondary svg{width:13px;height:13px;stroke:currentColor;stroke-width:2.2;fill:none;}
.stats-row{display:grid;grid-template-columns:repeat(2,1fr);gap:8px;margin-bottom:12px;}
@media(min-width:600px){.stats-row{grid-template-columns:repeat(4,1fr);}}
.stat-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--r);padding:14px 16px;box-shadow:var(--shadow-sm);}
.stat-label{font-size:10px;color:var(--text-3);font-weight:600;margin-bottom:4px;text-transform:uppercase;letter-spacing:.06em;}
.stat-val{font-size:20px;font-weight:800;letter-spacing:-.4px;color:var(--text);}
.stat-val.orange{color:var(--orange);}
.card{background:var(--surface);border:1px solid var(--border);border-radius:var(--r);box-shadow:var(--shadow-sm);overflow:hidden;margin-bottom:12px;animation:fadeUp .2s ease;}
.card-head{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--border);}
.card-title{font-size:12px;font-weight:800;color:var(--text);}
.card-badge{font-size:10px;font-weight:700;padding:2px 8px;border-radius:20px;background:var(--bg);color:var(--text-3);}
.card-body{padding:0;}
table{width:100%;border-collapse:collapse;font-size:12px;}
th{padding:9px 14px;text-align:left;font-size:10px;font-weight:700;color:var(--text-3);text-transform:uppercase;letter-spacing:.08em;border-bottom:1px solid var(--border);background:var(--bg);}
td{padding:9px 14px;border-bottom:1px solid var(--border);color:var(--text-2);}
tr:last-child td{border-bottom:none;}
tr:hover td{background:var(--bg);}
td.num{text-align:right;font-weight:700;color:var(--text);}
td.green{color:var(--green);}td.red{color:var(--red);}td.amber{color:var(--amber);}
td.rank{width:36px;text-align:center;}
.rank-badge{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:5px;font-size:10px;font-weight:800;background:var(--bg);color:var(--text-3);}
.rank-badge.g1{background:rgba(245,158,11,.12);color:#d97706;}
.rank-badge.g2{background:rgba(156,163,175,.12);color:#6b7280;}
.rank-badge.g3{background:rgba(180,120,60,.10);color:#92400e;}
.empty{padding:32px;text-align:center;color:var(--text-3);font-size:12px;font-weight:600;}
.spinner{width:22px;height:22px;border:2.5px solid var(--border);border-top-color:var(--orange);border-radius:50%;animation:spin .7s linear infinite;margin:28px auto;display:block;}
.error-box{padding:16px 18px;background:var(--red-lt);border-radius:var(--r);color:var(--red);font-size:12px;font-weight:600;margin-bottom:12px;}
.grid2{display:grid;grid-template-columns:1fr;gap:12px;}
@media(min-width:680px){.grid2{grid-template-columns:1fr 1fr;}}
.bar-row{display:flex;align-items:center;gap:10px;padding:8px 16px;border-bottom:1px solid var(--border);}
.bar-row:last-child{border-bottom:none;}
.bar-label{font-size:11.5px;font-weight:700;color:var(--text);width:130px;flex-shrink:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.bar-track{flex:1;height:6px;background:var(--bg);border-radius:6px;overflow:hidden;}
.bar-fill{height:100%;border-radius:6px;background:var(--orange);}
.bar-fill.blue{background:var(--blue);}
.bar-val{font-size:11.5px;font-weight:800;color:var(--text);flex-shrink:0;min-width:80px;text-align:right;}
.ovwrap{overflow-x:auto;}
.alerta{display:flex;align-items:flex-start;gap:12px;padding:14px 16px;border-radius:var(--r);margin-bottom:8px;border:1px solid;}
.alerta.ok{background:var(--green-lt);border-color:rgba(16,185,129,.3);color:#065f46;}
.alerta.warn{background:var(--amber-lt);border-color:rgba(245,158,11,.3);color:#78350f;}
.alerta.danger{background:var(--red-lt);border-color:rgba(239,68,68,.3);color:#7f1d1d;}
.alerta-icon{font-size:18px;line-height:1;flex-shrink:0;}
.alerta-body{flex:1;}
.alerta-title{font-size:12px;font-weight:800;margin-bottom:2px;}
.alerta-desc{font-size:11px;font-weight:500;opacity:.85;}
.alerta-meta{font-size:10px;margin-top:4px;opacity:.7;}
.retiros-kpi{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;padding:14px 16px;border-bottom:1px solid var(--border);}
.rkpi{text-align:center;}
.rkpi-label{font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3);margin-bottom:3px;}
.rkpi-val{font-size:16px;font-weight:800;}
.rkpi-val.red{color:var(--red);}
.rkpi-val.green{color:var(--green);}
.rkpi-val.amber{color:var(--amber);}
.ratio-bar-wrap{padding:12px 16px;border-bottom:1px solid var(--border);}
.ratio-label{font-size:10px;font-weight:700;color:var(--text-3);margin-bottom:6px;text-transform:uppercase;letter-spacing:.06em;}
.ratio-bar{display:flex;height:10px;border-radius:6px;overflow:hidden;gap:2px;}
.ratio-seg{height:100%;border-radius:4px;transition:width .4s ease;}
.ratio-legend{display:flex;gap:12px;margin-top:6px;}
.ratio-dot{display:inline-block;width:8px;height:8px;border-radius:2px;margin-right:4px;vertical-align:middle;}
.ratio-item{font-size:10px;font-weight:600;color:var(--text-2);}
.mini-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:8px;padding:12px 16px;}
@media(min-width:720px){.mini-grid{grid-template-columns:repeat(4,1fr);}}
.mini-kpi{background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:10px 12px;}
.mini-label{font-size:9px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--text-3);margin-bottom:3px;}
.mini-val{font-size:14px;font-weight:800;color:var(--text);}
.muted{color:var(--text-3);font-size:10px;font-weight:600;}
.nowrap{white-space:nowrap;}
</style>
<link rel="stylesheet" href="/css/responsive.css?v=406r"/>
</head>
<body>
<div class="topbar header-report no-print">
  <div class="topbar-icon"><svg viewBox="0 0 24 24"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg></div>
  <h1 class="header-title">Reporte de Ventas</h1>
  <div class="header-actions">
    <button class="btn-secondary" type="button" onclick="volverDashboard()">
      <svg viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg>
      Volver
    </button>
    <button class="btn-secondary" type="button" onclick="cargar()">
      <svg viewBox="0 0 24 24"><path d="M21 12a9 9 0 1 1-2.64-6.36"/><polyline points="21 3 21 9 15 9"/></svg>
      Actualizar
    </button>
    <button class="btn-secondary" type="button" onclick="window.print()">
      <svg viewBox="0 0 24 24"><path d="M6 9V2h12v7"/><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"/><path d="M6 14h12v8H6z"/></svg>
      Imprimir
    </button>
  </div>
</div>
<div class="container main-container">
  <div class="filters-card filtros">
    <div class="fg"><div class="fl">Fecha inicio</div><input type="date" id="f-inicio"/></div>
    <div class="fg"><div class="fl">Fecha fin</div><input type="date" id="f-fin"/></div>
    <button class="btn-primary" onclick="cargar()">
      <svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
      Consultar
    </button>
    <button class="btn-primary" id="btn-excel" onclick="descargarExcel()" style="background:#1a7a3f;" title="Descarga el reporte financiero semanal en Excel (máx. 7 días)">
      <svg viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>
      Excel Semanal
    </button>
  </div>
  <div id="error-box" class="error-box" style="display:none;"></div>
  <div id="spinner" class="spinner" style="display:none;"></div>
  <div id="resultado" style="display:none;">
    <div class="stats-row" id="stats-row"></div>
    <div id="alertas-retiros"></div>
    <div class="grid2">
      <div class="card">
        <div class="card-head"><span class="card-title">Formas de pago</span></div>
        <div class="card-body" id="formas-body"></div>
      </div>
      <div class="card">
        <div class="card-head"><span class="card-title">Por tipo de servicio</span></div>
        <div class="card-body" id="servicio-body"></div>
      </div>
    </div>
    <div class="card" id="card-retiros" style="display:none;">
      <div class="card-head"><span class="card-title">Retiros de caja vs Ventas</span><span class="card-badge" id="retiros-badge"></span></div>
      <div id="retiros-kpi" class="retiros-kpi"></div>
      <div class="ratio-bar-wrap" id="ratio-bar-wrap"></div>
      <div class="ovwrap">
        <table><thead><tr><th>Concepto</th><th>Tipo</th><th style="text-align:right">Importe</th></tr></thead>
        <tbody id="retiros-body"></tbody></table>
      </div>
    </div>
    <div class="grid2">
      <div class="card">
        <div class="card-head"><span class="card-title">Totales del Corte Z</span></div>
        <div class="mini-grid" id="operativo-body"></div>
      </div>
      <div class="card">
        <div class="card-head"><span class="card-title">Folios y control</span></div>
        <div class="mini-grid" id="folios-body"></div>
      </div>
    </div>
    <div class="card">
      <div class="card-head"><span class="card-title">Turnos incluidos</span><span class="card-badge" id="turnos-badge"></span></div>
      <div class="ovwrap">
        <table><thead><tr><th>Turno</th><th>Cajero</th><th>Apertura</th><th>Cierre</th><th>Tickets</th><th style="text-align:right">Venta</th></tr></thead>
        <tbody id="turnos-body"></tbody></table>
      </div>
    </div>
    <div class="card">
      <div class="card-head"><span class="card-title">Detalle de tickets</span><span class="card-badge" id="tickets-badge"></span></div>
      <div class="ovwrap report-scroll">
        <table><thead><tr><th>Folio</th><th>Fecha</th><th>Mesa</th><th>Mesero</th><th>Servicio</th><th>Pago</th><th style="text-align:right">Total</th></tr></thead>
        <tbody id="tickets-body"></tbody></table>
      </div>
    </div>
    <div class="grid2">
      <div class="card">
        <div class="card-head"><span class="card-title">Declaracion de caja</span><span class="card-badge" id="declaracion-badge"></span></div>
        <div class="ovwrap">
          <table><thead><tr><th>Turno</th><th>Forma</th><th style="text-align:right">Declarado</th></tr></thead>
          <tbody id="declaracion-body"></tbody></table>
        </div>
      </div>
      <div class="card">
        <div class="card-head"><span class="card-title">Cancelaciones</span><span class="card-badge" id="cancelaciones-badge"></span></div>
        <div class="ovwrap">
          <table><thead><tr><th>Concepto</th><th>Cantidad</th><th style="text-align:right">Importe</th></tr></thead>
          <tbody id="cancelaciones-body"></tbody></table>
        </div>
      </div>
    </div>
    <div class="card">
      <div class="card-head"><span class="card-title">Top productos más vendidos</span></div>
      <div class="ovwrap report-scroll">
        <table><thead><tr><th class="rank">Pos.</th><th>Producto</th><th>Cantidad</th><th style="text-align:right">Total</th></tr></thead>
        <tbody id="prod-body"></tbody></table>
      </div>
    </div>
    <div class="card">
      <div class="card-head"><span class="card-title">Ventas por hora del día</span></div>
      <div class="ovwrap">
        <table><thead><tr><th>Hora</th><th>Tickets</th><th style="text-align:right">Venta</th></tr></thead>
        <tbody id="hora-body"></tbody></table>
      </div>
    </div>
    <div class="card">
      <div class="card-head"><span class="card-title">Meseros — rendimiento</span></div>
      <div class="ovwrap">
        <table><thead><tr><th>Mesero</th><th>Tickets</th><th>Ticket prom.</th><th>Descuentos</th><th style="text-align:right">Venta total</th></tr></thead>
        <tbody id="mes-body"></tbody></table>
      </div>
    </div>
  </div>
</div>
<script src="/js/arkhon-utils.js"></script>
<script>
var LOCAL_API_KEY = '';
// token via _initAuth() de arkhon-utils.js
// token loaded via _initAuth()
const fmtPct=n=>`${Number(n||0).toFixed(1)}%`;
const esc=v=>String(v??'').replace(/[&<>"']/g,m=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[m]));
const fmtDate=v=>v?new Date(v).toLocaleString('es-MX',{day:'2-digit',month:'2-digit',hour:'2-digit',minute:'2-digit'}):'--';
const miniKpi=(label,value,cls='')=>`<div class="mini-kpi"><div class="mini-label">${label}</div><div class="mini-val ${cls}">${value}</div></div>`;


document.getElementById('f-inicio').value=hoy();

async function descargarExcel() {
  const ini = document.getElementById('f-inicio').value;
  const fin  = document.getElementById('f-fin').value;
  if (!ini || !fin) { showError('Selecciona fecha de inicio y fin.'); return; }
  if (ini > fin)    { showError('La fecha de inicio debe ser anterior o igual a la de fin.'); return; }
  const dias = Math.round((new Date(fin) - new Date(ini)) / 86400000) + 1;
  if (dias > 7) { showError('El reporte Excel semanal soporta máximo 7 días por hoja.'); return; }

  const btn = document.getElementById('btn-excel');
  const originalHTML = btn.innerHTML;
  btn.disabled = true;
  btn.innerHTML = '<svg viewBox="0 0 24 24" width="13" height="13" stroke="currentColor" stroke-width="2" fill="none"><line x1="12" y1="2" x2="12" y2="6"/><line x1="12" y1="18" x2="12" y2="22"/><line x1="4.93" y1="4.93" x2="7.76" y2="7.76"/><line x1="16.24" y1="16.24" x2="19.07" y2="19.07"/><line x1="2" y1="12" x2="6" y2="12"/><line x1="18" y1="12" x2="22" y2="12"/><line x1="4.93" y1="19.07" x2="7.76" y2="16.24"/><line x1="16.24" y1="7.76" x2="19.07" y2="4.93"/></svg> Generando...';

  try {
    const url = `/api/reporte-semanal/excel?inicio=${ini}&fin=${fin}`;
    // Incluir el token de sesión igual que apiFetch
    const resp = await fetch(url, {
      credentials: 'include',
      headers: { 'X-Api-Token': window.LOCAL_API_KEY || '' },
    });

    // Si la sesión expiró, intentar refresh silencioso
    if (resp.status === 401) {
      try {
        const rr = await fetch('/api/auth/refresh', { method:'POST', credentials:'include' });
        const rd = await rr.json();
        if (rd.ok && rd.token) {
          window.LOCAL_API_KEY = rd.token;
          // Reintentar con el token nuevo
          const resp2 = await fetch(url, {
            credentials: 'include',
            headers: { 'X-Api-Token': rd.token },
          });
          if (!resp2.ok) {
            const err2 = await resp2.json().catch(() => ({}));
            throw new Error(err2.error || 'Error al generar Excel');
          }
          const blob2 = await resp2.blob();
          if (blob2.size < 100) throw new Error('El archivo generado está vacío.');
          const cd2   = resp2.headers.get('content-disposition') || '';
          const m2    = cd2.match(/filename[^;=\n]*=(['"]*)?(.*?)\1(;|$)/i);
          const fname2 = m2 ? m2[2] : `Reporte_${ini}_${fin}.xlsx`;
          const a2 = document.createElement('a');
          a2.href = URL.createObjectURL(blob2);
          a2.download = fname2;
          document.body.appendChild(a2); a2.click();
          document.body.removeChild(a2);
          URL.revokeObjectURL(a2.href);
          btn.style.background = '#1a7a3f';
          btn.innerHTML = 'Descargado';
          setTimeout(() => { btn.disabled = false; btn.innerHTML = originalHTML; btn.style.background = ''; }, 2500);
          return;
        }
      } catch(_) {}
      // Si el refresh falla, redirigir al login
      window.location.href = '/login';
      return;
    }

    if (!resp.ok) {
      const ct = resp.headers.get('content-type') || '';
      let msg = 'Error al generar Excel';
      if (ct.includes('application/json')) {
        const err = await resp.json().catch(() => ({}));
        msg = err.error || msg;
      }
      throw new Error(msg);
    }

    const blob = await resp.blob();
    if (blob.size < 100) throw new Error('El archivo generado está vacío — revisa los datos del período.');

    // Obtener nombre del archivo desde Content-Disposition
    const cd   = resp.headers.get('content-disposition') || '';
    const match = cd.match(/filename[^;=\n]*=(['"]*)(.*?)\1(;|$)/i);
    const fname  = match ? match[2] : `Reporte_${ini}_${fin}.xlsx`;

    const a = document.createElement('a');
    a.href = URL.createObjectURL(blob);
    a.download = fname;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(a.href);

    // Feedback visual breve
    btn.style.background = '#1a7a3f';
    btn.innerHTML = 'Descargado';
    setTimeout(() => { btn.disabled = false; btn.innerHTML = originalHTML; btn.style.background = ''; }, 2500);
    return;
  } catch(e) {
    showError(e.message);
  }
  btn.disabled = false;
  btn.innerHTML = originalHTML;
}

// Al cargar la página, verificar si exceljs está disponible
(async function checkExcelStatus() {
  try {
    const s = await fetch('/api/reporte-semanal/status', {
      credentials: 'include',
      headers: { 'X-Api-Token': window.LOCAL_API_KEY || '' },
    });
    if (!s.ok) return;
    const d = await s.json();
    const btn = document.getElementById('btn-excel');
    if (!btn) return;
    if (!d.ok) {
      btn.title = 'exceljs no instalado — ejecuta ACTUALIZAR-VERSION.bat';
      btn.style.opacity = '0.5';
      btn.style.cursor  = 'not-allowed';
      btn.onclick = () => showError('El módulo de Excel no está instalado. Ejecuta ACTUALIZAR-VERSION.bat como Administrador y reinicia ARKHON.');
    }
  } catch(_) {}
})();
document.getElementById('f-fin').value=hoy();

let reportLoading = false;

async function cargar(options = {}){
  const silent = options && options.silent === true;
  if (reportLoading) return;
  const ini=document.getElementById('f-inicio').value;
  const fin=document.getElementById('f-fin').value;
  if(!ini||!fin){showError('Selecciona fecha de inicio y fin.');return;}
  if(ini>fin){showError('La fecha de inicio debe ser anterior o igual a la de fin.');return;}

  reportLoading = true;
  document.getElementById('error-box').style.display='none';
  if (!silent) {
    document.getElementById('resultado').style.display='none';
    document.getElementById('spinner').style.display='block';
  }

  try{
    const q=`?inicio=${ini}&fin=${fin}`;
    const[rep,hora,prods,meseros,retiros]=await Promise.all([
      api(`/reportes${q}`),
      api(`/dashboard/ventas-hora?fechaDesde=${ini}&fechaHasta=${fin}`).catch(()=>null),
      api(`/productos/top?fechaDesde=${ini}&fechaHasta=${fin}`).catch(()=>null),
      api(`/meseros/rendimiento?fechaDesde=${ini}&fechaHasta=${fin}`).catch(()=>null),
      api(`/retiros-caja?inicio=${ini}&fin=${fin}`).catch(()=>null),
    ]);
    if(!rep) throw new Error('No se pudieron cargar los datos del reporte');
    renderResultado(rep,hora,prods,meseros,retiros);
  }catch(e){if(!silent) showError('Error al cargar datos: '+e.message);}
  finally{
    reportLoading = false;
    if(!silent) document.getElementById('spinner').style.display='none';
  }
}

function rangoIncluyeHoy(){
  const ini=document.getElementById('f-inicio').value;
  const fin=document.getElementById('f-fin').value;
  const actual=hoy();
  return Boolean(ini && fin && ini<=actual && actual<=fin);
}

// El reporte comparte el ritmo operativo del monitor: mientras el rango incluya
// hoy, vuelve a consultar sin parpadeos ni intervención del usuario.
setInterval(()=>{
  if(document.visibilityState==='visible' && rangoIncluyeHoy()) cargar({silent:true});
},5000);
document.addEventListener('visibilitychange',()=>{
  if(document.visibilityState==='visible' && rangoIncluyeHoy()) cargar({silent:true});
});

function showError(msg){
  document.getElementById('spinner').style.display='none';
  const eb=document.getElementById('error-box');
  eb.textContent=msg;eb.style.display='block';
}

function volverDashboard(){
  if (window.self !== window.top) {
    window.parent.postMessage({ tipo: 'nav_dashboard' }, '*');
    return;
  }
  if (window.history.length > 1) {
    window.history.back();
    return;
  }
  window.location.href = '/';
}

function renderResultado(rep,hora,prods,meseros,retiros){
  const t=rep.totales||{};
  const venta=t.venta_total||0;
  const tickets=t.tickets||0;
  const descuentos=t.descuentos||0;
  const tickProm=tickets>0?venta/tickets:0;

  document.getElementById('stats-row').innerHTML=`
    <div class="stat-card"><div class="stat-label">Venta total</div><div class="stat-val orange">${fmt(venta)}</div></div>
    <div class="stat-card"><div class="stat-label">Tickets cerrados</div><div class="stat-val">${tickets}</div></div>
    <div class="stat-card"><div class="stat-label">Ticket promedio</div><div class="stat-val">${tickets>0?fmt(tickProm):'—'}</div></div>
    <div class="stat-card"><div class="stat-label">Descuentos</div><div class="stat-val">${fmt(descuentos)}</div></div>
  `;

  const fp=rep.formasPago||[];
  const fpTotal=fp.reduce((a,f)=>a+(f.total||0),0);
  document.getElementById('formas-body').innerHTML=fp.length?fp.map(f=>{
    const pct=fpTotal>0?Math.round(((f.total||0)/fpTotal)*100):0;
    return`<div class="bar-row"><div class="bar-label">${f.forma_pago||'—'}</div><div class="bar-track"><div class="bar-fill" style="width:${pct}%"></div></div><div class="bar-val">${fmt(f.total||0)}</div></div>`;
  }).join(''):'<div class="empty">Sin datos</div>';

  const vs=rep.ventasServicio||[];
  const vsTotal=vs.reduce((a,s)=>a+(s.total||0),0);
  document.getElementById('servicio-body').innerHTML=vs.length?vs.map(s=>{
    const pct=vsTotal>0?Math.round(((s.total||0)/vsTotal)*100):0;
    return`<div class="bar-row"><div class="bar-label">${s.servicio||'—'}</div><div class="bar-track"><div class="bar-fill" style="width:${pct}%"></div></div><div class="bar-val">${fmt(s.total||0)}</div></div>`;
  }).join(''):'<div class="empty">Sin datos</div>';

  renderRetiros(retiros, venta);
  renderDetalleCorte(rep);

  const tops=((rep.top_productos||[]).length ? rep.top_productos : (prods||[])).slice(0,20);
  document.getElementById('prod-body').innerHTML=tops.length?tops.map((p,i)=>{
    const rc=i===0?'g1':i===1?'g2':i===2?'g3':'';
    return`<tr><td class="rank"><span class="rank-badge ${rc}">${i+1}</span></td><td>${p.producto||p.descripcion||'—'}</td><td>${p.cantidad_vendida||p.cantidad||0}</td><td class="num green">${fmt(p.total_venta||p.total||0)}</td></tr>`;
  }).join(''):'<tr><td colspan="4" class="empty">Sin datos</td></tr>';

  const filas=(Array.isArray(rep.ventasHora) && rep.ventasHora.length ? rep.ventasHora : ((hora&&hora.filas)||(Array.isArray(hora)?hora:[])));
  const horas=filas.filter(h=>(h.venta||0)>0).sort((a,b)=>Number(a.hora)-Number(b.hora));
  document.getElementById('hora-body').innerHTML=horas.length?horas.map(h=>`
    <tr><td>${String(h.hora).padStart(2,'0')}:00 hrs</td><td>${h.tickets||0}</td><td class="num green">${fmt(h.venta||0)}</td></tr>
  `).join(''):'<tr><td colspan="3" class="empty">Sin datos</td></tr>';

  const mes=(Array.isArray(rep.meseros) && rep.meseros.length ? rep.meseros : (meseros||[]));
  document.getElementById('mes-body').innerHTML=mes.length?mes.map(m=>`
    <tr>
      <td style="font-weight:700">${m.mesero||m.nombre||'—'}</td>
      <td>${m.tickets||0}</td>
      <td>${fmt(m.ticket_promedio||0)}</td>
      <td class="red">${m.descuentos>0?fmt(m.descuentos):'—'}</td>
      <td class="num green">${fmt(m.venta_total||m.venta||m.total||0)}</td>
    </tr>
  `).join(''):'<tr><td colspan="5" class="empty">Sin datos</td></tr>';

  document.getElementById('resultado').style.display='block';
}

function renderDetalleCorte(rep){
  const op=rep.resumenOperativo||{};
  document.getElementById('operativo-body').innerHTML=[
    miniKpi('Subtotal',fmt(op.subtotal||0)),
    miniKpi('Impuestos',fmt(op.impuestos||0)),
    miniKpi('Propinas',fmt(op.propinas||0),'green'),
    miniKpi('Cargos',fmt(op.cargos||0)),
    miniKpi('Cortesias',fmt(op.cortesias||0),'amber'),
    miniKpi('Desc. monedero',fmt(op.descuento_monedero||0),'red'),
    miniKpi('Personas',op.personas||0),
    miniKpi('Articulos',op.articulos||0),
  ].join('');

  const f=rep.folios||{};
  document.getElementById('folios-body').innerHTML=[
    miniKpi('Folio inicial',f.folio_inicial||'--'),
    miniKpi('Folio final',f.folio_final||'--'),
    miniKpi('Cuentas pagadas',f.cuentas_pagadas||0),
    miniKpi('Canceladas',f.cuentas_canceladas||0,'red'),
    miniKpi('Con descuento',f.cuentas_con_descuento||0,'amber'),
    miniKpi('Con cortesia',f.cuentas_con_cortesia||0,'amber'),
    miniKpi('Reimpresiones',f.reimpresiones||0),
    miniKpi('Reabiertas',f.reabiertas||0),
  ].join('');

  const turnos=rep.turnos||[];
  document.getElementById('turnos-badge').textContent=`${turnos.length} turno${turnos.length!==1?'s':''}`;
  document.getElementById('turnos-body').innerHTML=turnos.length?turnos.map(t=>`
    <tr>
      <td style="font-weight:800">${esc(t.idturno||'--')}</td>
      <td>${esc(t.cajero||'--')}<div class="muted">${esc(t.estacion||'')}</div></td>
      <td class="nowrap">${fmtDate(t.apertura)}</td>
      <td class="nowrap">${fmtDate(t.cierre)}</td>
      <td>${t.tickets||0}</td>
      <td class="num green">${fmt(t.venta||0)}</td>
    </tr>
  `).join(''):'<tr><td colspan="6" class="empty">Sin turnos</td></tr>';

  const pagosPorFolio=(rep.pagosDetalle||[]).reduce((acc,p)=>{
    const key=String(p.folio);
    const current=acc[key]||[];
    current.push(`${esc(p.forma_pago||p.idformadepago||'Pago')} ${fmt(p.importe||0)}`);
    acc[key]=current;
    return acc;
  },{});
  const tickets=rep.detalleTickets||[];
  document.getElementById('tickets-badge').textContent=`${tickets.length} ticket${tickets.length!==1?'s':''}${tickets.length>=500?' mostrados':''}`;
  document.getElementById('tickets-body').innerHTML=tickets.length?tickets.map(t=>{
    const pagos=(pagosPorFolio[String(t.folio)]||[]).join('<br>');
    return `<tr>
      <td><b>${esc(t.folio)}</b><div class="muted">#${esc(t.numcheque||'--')}</div></td>
      <td class="nowrap">${fmtDate(t.fecha)}</td>
      <td>${esc(t.mesa||'--')}<div class="muted">${t.nopersonas||0} pax</div></td>
      <td>${esc(t.mesero||'Sin mesero')}</td>
      <td>${esc(t.servicio||'--')}</td>
      <td>${pagos||'<span class="muted">Sin pago</span>'}</td>
      <td class="num green">${fmt(t.total||0)}${t.propina>0?`<div class="muted">Propina ${fmt(t.propina)}</div>`:''}</td>
    </tr>`;
  }).join(''):'<tr><td colspan="7" class="empty">Sin tickets</td></tr>';

  const dec=rep.declaracionCaja||[];
  document.getElementById('declaracion-badge').textContent=dec.length?`${dec.length} linea${dec.length!==1?'s':''}`:'Sin captura';
  document.getElementById('declaracion-body').innerHTML=dec.length?dec.map(d=>`
    <tr><td>${esc(d.idturno||'--')}</td><td>${esc(d.forma_pago||d.descripcion||d.idformadepago||'--')}</td><td class="num">${fmt(d.importe_declarado||0)}</td></tr>
  `).join(''):'<tr><td colspan="3" class="empty">Declaracion no capturada</td></tr>';

  const cr=(rep.cancelaciones&&rep.cancelaciones.resumen)||{};
  const cancelRows=[
    { concepto:'Cuentas canceladas', cantidad:cr.cuentas_canceladas||0, importe:cr.importe_cuentas||0 },
    { concepto:'Productos cancelados', cantidad:cr.productos_cancelados||0, importe:cr.importe_productos||0 },
  ];
  document.getElementById('cancelaciones-badge').textContent=`${(cr.cuentas_canceladas||0)+(cr.productos_cancelados||0)} eventos`;
  document.getElementById('cancelaciones-body').innerHTML=cancelRows.map(r=>`
    <tr><td>${r.concepto}</td><td>${r.cantidad}</td><td class="num red">${fmt(r.importe||0)}</td></tr>
  `).join('');
}

function renderRetiros(retiros,ventas){
  const alertasEl=document.getElementById('alertas-retiros');
  const cardEl=document.getElementById('card-retiros');
  alertasEl.innerHTML='';
  cardEl.style.display='none';
  if(!retiros||!retiros.resumen)return;

  const r=retiros.resumen;
  const totalRetiros=r.total_retiros||0;
  const totalDep=r.total_depositos||0;
  const total=r.total_movimientos||0;

  if(total===0)return;
  cardEl.style.display='block';
  document.getElementById('retiros-badge').textContent=`${total} movimiento${total!==1?'s':''}`;

  const ratio=ventas>0?(totalRetiros/ventas)*100:0;
  let nivel='ok',icon='',titulo='Retiros dentro de rango normal',desc='';
  if(ratio>25){nivel='danger';icon='!';titulo='ALERTA: Retiros excesivos vs ventas';desc=`Los retiros de caja representan el ${fmtPct(ratio)} de las ventas del período.`;}
  else if(ratio>12){nivel='warn';icon='!️';titulo='Retiros elevados respecto a ventas';desc=`Los retiros representan el ${fmtPct(ratio)} de las ventas. Revisar justificaciones.`;}
  else{desc=`Retiros: ${fmtPct(ratio)} del total de ventas — dentro de parámetros normales.`;}

  if(ratio>0){
    alertasEl.innerHTML=`
      <div class="alerta ${nivel}">
        <div class="alerta-icon">${icon}</div>
        <div class="alerta-body">
          <div class="alerta-title">${titulo}</div>
          <div class="alerta-desc">${desc}</div>
          <div class="alerta-meta">Ventas: ${fmt(ventas)} · Retiros: ${fmt(totalRetiros)} · Depósitos: ${fmt(totalDep)}</div>
        </div>
      </div>`;
  }

  document.getElementById('retiros-kpi').innerHTML=`
    <div class="rkpi"><div class="rkpi-label">Retiros</div><div class="rkpi-val red">${fmt(totalRetiros)}</div></div>
    <div class="rkpi"><div class="rkpi-label">Depósitos</div><div class="rkpi-val green">${fmt(totalDep)}</div></div>
    <div class="rkpi"><div class="rkpi-label">% Retiros/Ventas</div><div class="rkpi-val ${ratio>25?'red':ratio>12?'amber':'green'}">${fmtPct(ratio)}</div></div>
  `;

  const tot=totalRetiros+totalDep||1;
  const rPct=Math.round((totalRetiros/tot)*100);
  const dPct=100-rPct;
  document.getElementById('ratio-bar-wrap').innerHTML=`
    <div class="ratio-label">Composición de movimientos de caja</div>
    <div class="ratio-bar">
      <div class="ratio-seg" style="width:${rPct}%;background:var(--red)"></div>
      <div class="ratio-seg" style="width:${dPct}%;background:var(--green)"></div>
    </div>
    <div class="ratio-legend">
      <span class="ratio-item"><span class="ratio-dot" style="background:var(--red)"></span>Retiros ${fmtPct(rPct)}</span>
      <span class="ratio-item"><span class="ratio-dot" style="background:var(--green)"></span>Depósitos ${fmtPct(dPct)}</span>
    </div>`;

  const conceptos=retiros.porConcepto||[];
  document.getElementById('retiros-body').innerHTML=conceptos.length?conceptos.map(c=>{
    const tipo=c.tipo===2?'Depósito':c.tipo===3?'Propina':'Retiro';
    const cls=c.tipo===2?'green':c.tipo===3?'amber':'red';
    return`<tr><td>${c.concepto||'Sin concepto'}</td><td class="${cls}" style="font-weight:700">${tipo}</td><td class="num ${cls}">${fmt(c.importe_total||0)}</td></tr>`;
  }).join(''):'<tr><td colspan="3" class="empty">Sin movimientos</td></tr>';
}


  // Ocultar topbar si corre dentro de un iframe
  if (window.self !== window.top) {
    const tb = document.querySelector('.topbar');
    if (tb) tb.style.display = 'none';
  }
(async()=>{await _initAuth();cargar();})();
</script>
</body>
</html>
