<?php
/**
 * Mesas / Monitor — shell instantâneo.
 * KPIs e cards de mesas abertas carregados via fetch() após o DOM pronto.
 * TTFB = tempo de render PHP (<10ms), sem nenhuma query Firebird aqui.
 */
?>
<div class="pbi-page-header">
    <h1 class="pbi-page-title"><i class="bi bi-display me-2 text-accent"></i>Mesas</h1>
</div>
<?php include __DIR__ . '/_submenu.php' ?>

<div class="d-flex flex-wrap justify-content-between align-items-center mb-3 gap-2">
    <div class="pbi-hint" style="margin:0">Acompanhamento ao vivo das mesas ocupadas — atualiza sozinho a cada 15s. <span id="refresh-stamp" class="text-muted ms-2"></span></div>
    <div class="small d-flex flex-wrap gap-2">
        <span class="badge" style="background:#10b981">&lt; 1h recente</span>
        <span class="badge" style="background:#ca8a04">1–2h atenção</span>
        <span class="badge" style="background:#ea580c">2–3h demorada</span>
        <span class="badge" style="background:#dc2626">&gt; 3h crítica</span>
    </div>
</div>

<!-- ── KPIs skeleton ─────────────────────────────────────────────────────── -->
<div class="pbi-kpi-grid mb-4" id="kpi-grid">
    <?php for ($i = 0; $i < 2; $i++): ?>
    <div class="pbi-kpi-card">
        <div class="pbi-kpi-label pbi-skeleton" style="width:60%;height:.8rem;border-radius:4px">&nbsp;</div>
        <div class="pbi-kpi-value pbi-skeleton mt-2" style="width:80%;height:1.6rem;border-radius:4px">&nbsp;</div>
    </div>
    <?php endfor; ?>
</div>

<!-- ── Cards de mesas abertas (async) ────────────────────────────────────── -->
<div id="mesas-container">
    <div class="pbi-card">
        <div class="p-4 text-center text-muted">
            <div class="spinner-border spinner-border-sm text-accent me-2" role="status"></div>
            <span style="font-size:.85rem">Carregando mesas abertas…</span>
        </div>
    </div>
</div>

<!-- ── Config injetada pelo PHP para o JS usar ──────────────────────────── -->
<script>
window.__MESAS_MONITOR = {
    actionUrl: '/mesas/monitor'
};
</script>

<style>
@keyframes pbi-pulse {
  0%, 100% { opacity: 1; }
  50%       { opacity: .4; }
}
.pbi-skeleton {
  background: var(--pbi-border, #e2e8f0);
  animation: pbi-pulse 1.4s ease-in-out infinite;
  pointer-events: none;
  color: transparent !important;
}
/* KPIs do monitor: nao corta valor R$. Permite wrap, fonte menor, card menor. */
#kpi-grid {
  grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)) !important;
  gap: .75rem !important;
}
#kpi-grid .pbi-kpi-card {
  min-width: 0;
  padding: .75rem !important;
  gap: .5rem !important;
}
#kpi-grid .pbi-kpi-icon {
  width: 36px !important; height: 36px !important;
  flex-shrink: 0;
  font-size: 1.05rem !important;
}
#kpi-grid .pbi-kpi-body {
  min-width: 0;
  overflow: visible;
  flex: 1 1 auto;
}
#kpi-grid .pbi-kpi-value {
  font-size: 1.2rem !important;
  font-weight: 800;
  line-height: 1.1;
  white-space: normal;     /* permite quebrar */
  overflow-wrap: anywhere; /* nunca corta */
  word-break: keep-all;    /* mas nao quebra no meio do R$ */
  margin-top: 2px;
}
#kpi-grid .pbi-kpi-label {
  font-size: .65rem !important;
  letter-spacing: .03em;
  line-height: 1.15;
  white-space: normal;
}
#kpi-grid .pbi-kpi-sub {
  font-size: .68rem !important;
  white-space: normal;
  word-wrap: break-word;
  line-height: 1.2;
}
</style>

<script>
(function () {
'use strict';

function fmtR(v) {
    return 'R$ ' + parseFloat(v || 0).toLocaleString('pt-BR', {
        minimumFractionDigits: 2, maximumFractionDigits: 2
    });
}
function fmtN(v, d) {
    d = d === undefined ? 0 : d;
    return parseFloat(v || 0).toLocaleString('pt-BR', {
        minimumFractionDigits: d, maximumFractionDigits: d
    });
}
function esc(s) {
    var d = document.createElement('div');
    d.textContent = s == null ? '' : String(s);
    return d.innerHTML;
}
function apiFetch(url) {
    return fetch(url, { credentials: 'same-origin' })
        .then(function (r) {
            if (!r.ok) return r.json().then(function(e){ throw new Error(e.erro || 'HTTP ' + r.status); });
            return r.json();
        });
}

function parseAberturaISO(m) {
    // DATA_ABERTURA pode vir "2026-06-12" ou ISO. HORA_ABERTURA pode vir "21:23:00" ou só "21:23".
    var d = (m.DATA_ABERTURA || '').substring(0, 10);
    var h = (m.HORA_ABERTURA || '').substring(0, 8);
    if (h.length === 5) h += ':00';
    if (!d || !h) return null;
    var iso = d + 'T' + h;
    var t = new Date(iso).getTime();
    return isNaN(t) ? null : t;
}
function tempoAberta(m) {
    var t0 = parseAberturaISO(m);
    if (t0 === null) return null;
    var ms = Date.now() - t0;
    return ms < 0 ? 0 : ms;
}
var LIMITE_ESQUECIDA_MS = 24 * 3600 * 1000; // >24h = "esquecida" (mesa fantasma no ERP)

function corPorTempo(ms) {
    // verde <1h, amarelo 1-2h, laranja 2-3h, vermelho >3h, cinza-escuro esquecida >24h
    if (ms >= LIMITE_ESQUECIDA_MS) return { borda:'#475569', badge:'#334155', label:'esquecida' };
    if (ms < 3600000)              return { borda:'#10b981', badge:'#10b981', label:'recente' };
    if (ms < 2 * 3600000)          return { borda:'#facc15', badge:'#ca8a04', label:'atenção' };
    if (ms < 3 * 3600000)          return { borda:'#f97316', badge:'#ea580c', label:'demorada' };
    return                                { borda:'#ef4444', badge:'#dc2626', label:'crítica' };
}
function fmtDuracao(ms) {
    if (ms === null || isNaN(ms)) return '—';
    // Mesa esquecida: mostra dias, nao horas absurdas
    if (ms >= LIMITE_ESQUECIDA_MS) {
        var d = Math.floor(ms / (24 * 3600 * 1000));
        return d + 'd esquecida';
    }
    var s = Math.floor(ms / 1000);
    var h = Math.floor(s / 3600);
    var m = Math.floor((s % 3600) / 60);
    var sec = s % 60;
    if (h > 0) return h + 'h ' + (m < 10 ? '0' : '') + m + 'm';
    if (m > 0) return m + 'm ' + (sec < 10 ? '0' : '') + sec + 's';
    return sec + 's';
}
function fmtDataAbertura(m) {
    // "2017-03-12" → "12/03/2017"
    var d = (m.DATA_ABERTURA || '').substring(0, 10);
    if (!d || d.length < 10) return '';
    return d.substring(8,10) + '/' + d.substring(5,7) + '/' + d.substring(0,4);
}

function renderKpis(abertas) {
    var totalConsumo = abertas.reduce(function(s, m) { return s + parseFloat(m.TOTAL_ITENS || 0); }, 0);
    var ticketMedio = abertas.length ? (totalConsumo / abertas.length) : 0;
    // tempo medio: ignora mesas "esquecidas" (>24h) pra nao distorcer media
    var tempos = abertas.map(tempoAberta).filter(function(t){ return t !== null && t < LIMITE_ESQUECIDA_MS; });
    var tempoMedioMs = tempos.length ? (tempos.reduce(function(a,b){return a+b;}, 0) / tempos.length) : 0;
    var criticas = abertas.filter(function(m){ var t = tempoAberta(m); return t !== null && t >= 2 * 3600000 && t < LIMITE_ESQUECIDA_MS; }).length;
    var esquecidas = abertas.filter(function(m){ var t = tempoAberta(m); return t !== null && t >= LIMITE_ESQUECIDA_MS; }).length;

    var html = ''
        + kpiCard('rgba(16,185,129,0.12)', 'bi-grid-3x3-gap-fill', '#10b981', 'Mesas Abertas', abertas.length, 'em atendimento')
        + kpiCard('rgba(79,142,247,0.12)', 'bi-cash-coin',         '#4f8ef7', 'Consumo Aberto', fmtR(totalConsumo), 'soma das comandas')
        + kpiCard('rgba(168,85,247,0.12)', 'bi-cup-straw',         '#a855f7', 'Ticket Médio', fmtR(ticketMedio), 'por mesa agora')
        + kpiCard('rgba(245,158,11,0.12)', 'bi-clock-history',     '#f59e0b', 'Tempo Médio Aberta', fmtDuracao(tempoMedioMs), 'desconta esquecidas')
        + kpiCard('rgba(239,68,68,0.12)',  'bi-exclamation-triangle-fill', '#ef4444', 'Mesas em Atenção', criticas, '>2h abertas')
        + (esquecidas > 0 ? kpiCard('rgba(71,85,105,0.15)', 'bi-bug', '#475569', 'Esquecidas', esquecidas, 'abertas há +24h — limpar no ERP Fire Sistemas') : '')
    ;
    document.getElementById('kpi-grid').innerHTML = html;
}
function kpiCard(bgIcon, icon, color, label, value, sub) {
    return '<div class="pbi-kpi-card">'
        + '<div class="pbi-kpi-icon" style="background:' + bgIcon + '"><i class="bi ' + icon + '" style="color:' + color + '"></i></div>'
        + '<div class="pbi-kpi-body">'
        + '<div class="pbi-kpi-label">' + label + '</div>'
        + '<div class="pbi-kpi-value" style="color:' + color + '">' + value + '</div>'
        + '<div class="pbi-kpi-sub">' + sub + '</div>'
        + '</div></div>';
}

function renderMesas(abertas, itens) {
    if (!abertas.length) {
        document.getElementById('mesas-container').innerHTML =
            '<div class="pbi-card"><div class="p-5 text-center">'
            + '<i class="bi bi-grid-3x3-gap text-muted" style="font-size:3rem"></i>'
            + '<p class="mt-3 text-muted">Nenhuma mesa aberta no momento.</p>'
            + '</div></div>';
        return;
    }

    var cards = abertas.map(function(m) {
        var codAb = m.COD_ABERTURA;
        var itensMesa = itens[codAb] || [];
        var itensHtml = '';
        if (itensMesa.length) {
            var rows = itensMesa.map(function(it) {
                var obs = it.OBSERVACAO ? '<div class="text-muted" style="font-size:.72rem">' + esc(it.OBSERVACAO) + '</div>' : '';
                return '<tr>'
                    + '<td class="px-3">' + esc(it.DESCRICAO || '—') + obs + '</td>'
                    + '<td class="text-center">' + fmtN(it.QTD, 0) + '&times;</td>'
                    + '<td class="text-end px-3 fw-semibold">' + fmtR(it.SUBTOTAL) + '</td>'
                    + '</tr>';
            }).join('');
            itensHtml = '<div style="border-top:1px solid var(--pbi-border)">'
                + '<button class="btn btn-sm w-100 text-start px-3 py-2 d-flex justify-content-between align-items-center"'
                + ' style="background:var(--pbi-surface-2);border:none;color:var(--pbi-sidebar-text)"'
                + ' onclick="this.nextElementSibling.classList.toggle(\'d-none\');this.querySelector(\'i.toggle-icon\').classList.toggle(\'bi-chevron-up\');this.querySelector(\'i.toggle-icon\').classList.toggle(\'bi-chevron-down\')">'
                + '<span class="small fw-semibold"><i class="bi bi-list-ul me-1"></i>' + itensMesa.length + ' item(ns) lançado(s)</span>'
                + '<i class="bi bi-chevron-up small toggle-icon"></i>'
                + '</button>'
                + '<div style="max-height:220px;overflow-y:auto">'
                + '<table class="table table-sm mb-0" style="font-size:.78rem">'
                + '<thead style="background:var(--pbi-surface-2)"><tr>'
                + '<th class="px-3 text-muted fw-normal">Produto</th>'
                + '<th class="text-center text-muted fw-normal">Qtd</th>'
                + '<th class="text-end px-3 text-muted fw-normal">Total</th>'
                + '</tr></thead><tbody>' + rows + '</tbody></table></div></div>';
        } else {
            itensHtml = '<div class="px-3 pb-3 text-muted small text-center">Nenhum item lançado</div>';
        }

        var ms = tempoAberta(m);
        var cor = ms === null ? { borda:'var(--pbi-accent)', badge:'#6b7280', label:'—' } : corPorTempo(ms);
        var tempoTexto = ms === null ? '—' : fmtDuracao(ms);
        var t0 = parseAberturaISO(m);
        return '<div class="col-md-6 col-lg-4">'
            + '<div class="pbi-card h-100" style="border:2px solid ' + cor.borda + ';transition:border-color .3s">'
            + '<div class="pbi-card-header d-flex justify-content-between align-items-center" style="background:' + cor.borda + '15">'
            + '<span class="fw-bold"><i class="bi bi-grid-3x3-gap-fill me-1"></i>Mesa ' + esc(m.COD_MESA || '—') + '</span>'
            + '<span class="badge" style="background:' + cor.badge + ';color:#fff;font-size:.7rem">'
            +   '<i class="bi bi-clock me-1"></i>'
            +   '<span class="mesa-tempo" data-aberta-iso="' + (t0 || '') + '">' + tempoTexto + '</span>'
            + '</span>'
            + '</div>'
            + '<div class="px-3 pt-3 pb-2">'
            + '<div class="d-flex justify-content-between mb-1"><span class="text-muted small"><i class="bi bi-person-workspace me-1"></i>Garçom</span><span class="fw-semibold small">' + esc(m.GARCOM || '—') + '</span></div>'
            + '<div class="d-flex justify-content-between mb-1"><span class="text-muted small"><i class="bi bi-door-open me-1"></i>Abertura</span><span class="small">' + esc((m.HORA_ABERTURA || '—').substring(0, 5)) + (ms !== null && ms >= LIMITE_ESQUECIDA_MS ? ' — ' + esc(fmtDataAbertura(m)) : '') + '</span></div>'
            + '<div class="d-flex justify-content-between mb-2"><span class="text-muted small"><i class="bi bi-people me-1"></i>Pessoas</span><span class="small">' + parseInt(m.QTD_PESSOAS || 0) + '</span></div>'
            + '<div class="d-flex justify-content-between align-items-center py-2" style="border-top:1px solid var(--pbi-border)">'
            + '<span class="text-muted small fw-semibold">CONSUMO TOTAL</span>'
            + '<span class="fw-bold fs-6" style="color:' + cor.badge + '">' + fmtR(m.TOTAL_ITENS) + '</span>'
            + '</div></div>'
            + itensHtml
            + '</div></div>';
    }).join('');

    document.getElementById('mesas-container').innerHTML =
        '<div class="row g-3 mb-4">' + cards + '</div>';
}

var __lastAbertas = [];
function carregar() {
    apiFetch('/api/mesas/monitor')
        .then(function (d) {
            __lastAbertas = d.abertas || [];
            renderKpis(__lastAbertas);
            renderMesas(__lastAbertas, d.itens || {});
            var s = document.getElementById('refresh-stamp');
            if (s) s.textContent = 'atualizado ' + new Date().toLocaleTimeString('pt-BR');
        })
        .catch(function (e) {
            document.getElementById('kpi-grid').innerHTML =
                '<div class="alert alert-warning small col-span-2"><i class="bi bi-exclamation-triangle me-2"></i>' + esc(e.message) + '</div>';
            document.getElementById('mesas-container').innerHTML =
                '<div class="alert alert-warning small"><i class="bi bi-exclamation-triangle me-2"></i>Erro ao carregar mesas: ' + esc(e.message) + '</div>';
        });
}

// tick de 1s — atualiza tempo nos cards + recalcula KPIs derivados de tempo
function tickTempos() {
    var nodes = document.querySelectorAll('.mesa-tempo');
    nodes.forEach(function (el) {
        var iso = +el.getAttribute('data-aberta-iso');
        if (!iso) return;
        var ms = Date.now() - iso;
        if (ms < 0) ms = 0;
        el.textContent = fmtDuracao(ms);
    });
    // KPIs do tempo medio + atencao + esquecidas mudam com o relogio
    if (__lastAbertas.length) renderKpis(__lastAbertas);
}

window.addEventListener('DOMContentLoaded', function () {
    carregar();
    setInterval(tickTempos, 1000);   // tempo vivo
    setInterval(carregar, 15000);    // re-fetch servidor 15s
});

})();
</script>
