// ── ARKHON — Cliente API REST ─────────────────────────────────────────────────

window.ArkhonUtils = window.ArkhonUtils || {};

window.ArkhonUtils.normalizeMesas = window.ArkhonUtils.normalizeMesas || function normalizeMesas(input) {
  const mesas = Array.isArray(input) ? input : [];
  const seen = new Set();
  const output = [];

  for (const mesa of mesas) {
    if (!mesa || typeof mesa !== 'object') continue;
    const folio = Number(mesa.foliocuenta || mesa.folioCuenta || mesa.folio || 0);
    if (!folio || seen.has(folio)) continue;
    if (mesa.pagado === 1 || mesa.cancelado === 1 || mesa.activa === false || mesa.abierta === false) continue;
    seen.add(folio);
    output.push({ ...mesa, foliocuenta: folio });
  }

  return output;
};

window.ArkhonUtils.applyMesasSnapshot = window.ArkhonUtils.applyMesasSnapshot || function applyMesasSnapshot(source, mesas) {
  const previous = Array.isArray(window.cache && cache.mesas) ? cache.mesas : [];
  const next = window.ArkhonUtils.normalizeMesas(mesas);
  const nextFolios = new Set(next.map(m => Number(m.foliocuenta)));
  const removed = previous
    .map(m => Number(m && m.foliocuenta))
    .filter(folio => folio && !nextFolios.has(folio));

  cache.mesas = next;
  console.debug('[mesas]', source, { loaded: next.length, removed });
  return next;
};

/**
 * Fetch autenticado hacia la API de ARKHON.
 * Devuelve `data` si ok:true, o null en caso de error (con log en consola).
 * @param {string} ep  - endpoint relativo a /api, ej: '/dashboard/resumen'
 * @param {object} [opts] - opciones adicionales para fetch
 */
async function apiFetch(ep, opts = {}) {
  try {
    // Sanity check: detectar endpoints malformados que incluyan comillas literales
    if (typeof ep !== 'string' || ep.includes('"')) {
      console.error('[apiFetch] Endpoint malformado detectado:', ep);
      return null;
    }
    const res = await fetch(API_BASE + '/api' + ep, {
      ...opts,
      headers: {
        'bypass-tunnel-reminder': 'true',
        'User-Agent':   'ARKHON/4.0.5',
        'X-Api-Token':  LOCAL_API_KEY,
        ...(opts.headers || {}),
      },
    });

    // Detectar respuestas HTML (proxy error, Cloudflare error page, etc.)
    const contentType = res.headers.get('content-type') || '';
    if (contentType.includes('text/html')) {
      console.warn(`[apiFetch] ${ep} devolvió HTML (status ${res.status}) — posible error de red o autenticación`);
      return null;
    }

    const d = await res.json();
    if (d.ok) return d.data;

    // 401 → token expirado, redirigir a login
    if (res.status === 401) {
      console.warn(`[apiFetch] ${ep} → 401, redirigiendo a login`);
      window.location.href = '/login';
      return null;
    }

    console.error(`[apiFetch] ${ep} → error:`, d.error || `HTTP ${res.status}`);
    return null;
  } catch (e) {
    console.error(`[apiFetch] ${ep} → excepción:`, e.message);
    return null;
  }
}

/**
 * Carga todos los datos del dashboard en paralelo y llena el cache global.
 * Es idempotente: si ya hay una carga en curso la ignora.
 */
async function cargarDatos() {
  if (loading) {
    // Conservar la ultima seleccion hecha mientras una consulta anterior sigue
    // en vuelo. Al terminar se vuelve a consultar usando turno/periodo actuales.
    reloadQueued = true;
    return;
  }
  loading = true;
  try {
    const contextoSolicitud = [turno, estacion, periodoActual, fecha, fechaDesde, fechaHasta].join('|');
    const rangeQ = fechaDesde && fechaHasta
      ? `?fechaDesde=${fechaDesde}&fechaHasta=${fechaHasta}${turno ? `&turno=${turno}` : ''}`
      : `?fecha=${fecha}${turno ? `&turno=${turno}` : ''}`;
    const dataQ = rangeQ + (estacion ? `${rangeQ.includes('?') ? '&' : '?'}estacion=${encodeURIComponent(estacion)}` : '');

    const hoyStr = (() => {
      const d = new Date();
      return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`;
    })();
    const esHoy     = periodoActual === 'hoy' || (fechaDesde === hoyStr && fechaHasta === hoyStr);
    const turnosEp  = esHoy ? '/turnos/hoy' : `/turnos/historial${rangeQ}`;

    // Cargar metas de configuración en segundo plano (no bloquea el render principal)
    apiFetch('/metas').then(mc => {
      if (mc && typeof mc === 'object') {
        cache.metasConfig = {
          meta_diaria:   Number(mc.meta_diaria   || 0),
          meta_mensual:  Number(mc.meta_mensual  || 0),
          meta_anual:    Number(mc.meta_anual    || 0),
        };
        renderTab(currentTab);
      }
    });

    const updateClockAndRender = () => {
      const hora = new Date().toLocaleTimeString('es-MX', { hour: '2-digit', minute: '2-digit' });
      $('last-updated').innerHTML = `<svg viewBox="0 0 24 24" style="width:12px;height:12px;stroke:currentColor;stroke-width:2;fill:none;"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg> ${hora}`;
      renderTab(currentTab);
    };

    const [r, vh, vp, ms, tu] = await Promise.all([
      apiFetch(`/dashboard/resumen${dataQ}`),
      apiFetch(`/dashboard/ventas-hora${dataQ}`),
      apiFetch(`/dashboard/ventas-periodo${dataQ}`),
      apiFetch('/mesas'),
      apiFetch(turnosEp),
    ]);

    const contextoActual = [turno, estacion, periodoActual, fecha, fechaDesde, fechaHasta].join('|');
    if (contextoActual !== contextoSolicitud) {
      reloadQueued = true;
      return;
    }

    // BUG-FIX: usar !== null/undefined en vez de if(r) para que periodos con
    // venta_total=0 (inicio del día, sin ventas) actualicen el cache correctamente.
    // Antes: if(r) → falsy cuando la respuesta era {venta_total:0,...} → cache
    // conservaba el valor del período anterior (ej: Este mes con 500) y el
    // usuario veía ese valor stale al cambiar de vuelta a Hoy.
    if (r  != null) cache.resumen         = r;
    if (vh != null) { cache.ventasHora = vh.filas || vh; cache.ventasHoraMetricas = vh.metricas || null; }
    if (vp != null) cache.ventasPeriodo   = vp;
    if (ms != null || (turno && Array.isArray(r?.mesas))) {
      const mesasContexto = turno && Array.isArray(r?.mesas) ? r.mesas : ms;
      window.ArkhonUtils.applyMesasSnapshot(turno ? 'rest-turno' : 'rest', mesasContexto || []);
    }

    const me = null;
    if (me) {
      cache.meseros = me;
      // Cargar datos del día anterior para comparativa de meseros (no bloquea)
      const ayer = new Date();
      ayer.setDate(ayer.getDate() - 1);
      const ayerStr = ayer.toLocaleDateString('sv-SE');
      apiFetch(`/meseros/rendimiento?fechaDesde=${ayerStr}&fechaHasta=${ayerStr}`).then(ma => {
        if (ma) {
          const mp = {};
          ma.forEach(m => { mp[m.mesero || m.nombre || ''] = (m.venta_total || 0); });
          cache.meserosPrev = mp;
        }
      }).catch(() => {});
    }

    if (tu) { cache.turnos = tu; renderTurnosBtns(tu); }

    const hora = new Date().toLocaleTimeString('es-MX', { hour: '2-digit', minute: '2-digit' });
    $('last-updated').innerHTML = `<svg viewBox="0 0 24 24" style="width:12px;height:12px;stroke:currentColor;stroke-width:2;fill:none;"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg> ${hora}`;
    renderTab(currentTab);
    Promise.all([
      apiFetch(`/dashboard/ventas-mes?fecha=${fecha}`),
      apiFetch(`/dashboard/formas-pago${dataQ}`),
      apiFetch(`/dashboard/metas`),
      apiFetch(`/productos/top${dataQ}`),
      apiFetch(`/productos/por-grupo${dataQ}`),
      apiFetch(`/meseros/rendimiento${rangeQ}`),
      apiFetch('/retiros-caja/en-vivo').catch(() => null),
      apiFetch(`/dashboard/ventas-servicio${dataQ}`),
      apiFetch('/dashboard/domicilios').catch(() => null),
    ]).then(([vm, fp, mt, pr, pg, me2, ri, vs, dm]) => {
      if (vm != null) cache.ventasMes       = vm;
      if (fp != null) cache.formasPago      = fp;
      if (mt != null) cache.metas           = mt;
      if (dm != null) cache.domicilios      = dm;
      if (pr != null) cache.productos       = pr;
      if (pg != null) cache.porGrupo        = pg;
      if (vs != null) cache.ventasServicio  = vs;
      if (ri != null) cache.retirosDia      = ri;
      if (me2) {
        cache.meseros = me2;
        const ayer = new Date();
        ayer.setDate(ayer.getDate() - 1);
        const ayerStr = ayer.toLocaleDateString('sv-SE');
        apiFetch(`/meseros/rendimiento?fechaDesde=${ayerStr}&fechaHasta=${ayerStr}`).then(ma => {
          if (ma) {
            const mp = {};
            ma.forEach(m => { mp[m.mesero || m.nombre || ''] = (m.venta_total || 0); });
            cache.meserosPrev = mp;
          }
        }).catch(() => {});
      }
      updateClockAndRender();
    }).catch(e => console.warn('[cargarDatos:secundario]', e.message));
  } catch (e) {
    console.error('[cargarDatos]', e.message);
  } finally {
    loading    = false;
    countdown  = 300;
    if (reloadQueued) {
      reloadQueued = false;
      setTimeout(() => cargarDatos(), 0);
    }
  }
}

/**
 * Actualización manual forzada del dashboard.
 */
async function manualRefresh() {
  const btn = $('btn-refresh');
  if (!btn || btn.disabled) return;
  btn.disabled = true;
  btn.innerHTML = `<svg viewBox="0 0 24 24" style="width:13px;height:13px;stroke:#fff;stroke-width:2.2;fill:none;animation:spin .7s linear infinite"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 11-2.12-9.36L23 10"/></svg> Actualizando…`;
  try {
    if (currentTab === 'productos' && typeof prodReload === 'function') {
      await prodReload();
      return;
    }
    await fetch('/api/dashboard/refresh', { method: 'POST', headers: { 'X-Api-Token': LOCAL_API_KEY } });
    await cargarDatos();
  } catch (e) {
    console.error('[manualRefresh]', e.message);
  } finally {
    btn.disabled = false;
    btn.innerHTML = `<svg viewBox="0 0 24 24" style="width:13px;height:13px;stroke:#fff;stroke-width:2.2;fill:none;"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 11-2.12-9.36L23 10"/></svg> Actualizar`;
    countdown = 300;
  }
}
