<?php
/**
 * modules/turnero/views/historial.php
 * Historial consultable de turnos con filtros multi-día y paginación.
 */
require_once APP_ROOT . '/config/config.php';
if (!isUserLoggedIn()) { header('Location: ' . BASE_URL . 'login.php'); exit; }

Layout::open('Historial de Turnos', 'fas fa-history');
?>
<style>
    body { background:#f1f5f9; }

    /* ── Encabezado ── */
    .page-header {
        background:#fff; border-bottom:1px solid #e2e8f0;
        padding:12px 22px; display:flex; align-items:center; gap:10px; flex-wrap:wrap;
    }
    .page-header h1 { font-size:1.12rem; font-weight:700; color:#1e293b; margin:0; flex:1; min-width:150px; }

    /* ── Filtros ── */
    .filter-bar {
        background:#fff; border-bottom:1px solid #e2e8f0;
        padding:12px 22px; display:flex; align-items:flex-end; gap:10px; flex-wrap:wrap;
    }
    .filter-group { display:flex; flex-direction:column; gap:3px; }
    .filter-group label { font-size:.7rem; font-weight:600; text-transform:uppercase;
                          letter-spacing:.06em; color:#64748b; }
    .filter-group .form-control,
    .filter-group .form-select { font-size:.82rem; min-width:120px; }
    .filter-group.wide .form-control { min-width:200px; }

    /* ── Contenido ── */
    .content-wrap { max-width:1200px; margin:22px auto; padding:0 16px 60px; }

    /* ── KPIs resumen ── */
    .kpi-strip {
        display:flex; flex-wrap:wrap; gap:10px; margin-bottom:18px;
    }
    .kpi-chip {
        display:flex; align-items:center; gap:7px;
        background:#fff; border:1px solid #e2e8f0; border-radius:99px;
        padding:5px 14px; font-size:.8rem;
    }
    .kpi-chip .chip-val { font-weight:800; font-size:1rem; }
    .kpi-chip .chip-lbl { color:#64748b; }

    /* ── Tabla ── */
    .section-card { background:#fff; border:1px solid #e2e8f0; border-radius:12px;
                    padding:0; overflow:hidden; }
    .section-card .table { margin:0; }
    .section-card .table thead th {
        background:#f8fafc; font-size:.7rem; text-transform:uppercase;
        letter-spacing:.07em; color:#475569; font-weight:700;
        padding:10px 12px; white-space:nowrap; border-bottom:2px solid #e2e8f0;
    }
    .section-card .table tbody td { padding:9px 12px; font-size:.82rem; vertical-align:middle; }
    .section-card .table tbody tr:hover { background:#f8fafc; }

    /* ── Estado badges ── */
    .eb { font-size:.65rem; padding:2px 8px; border-radius:99px; font-weight:700; white-space:nowrap; }
    .eb-espera          { background:#fef9c3; color:#78350f; }
    .eb-en_recepcion    { background:#dbeafe; color:#1e40af; }
    .eb-en_espera_lugar { background:#fde68a; color:#92400e; }
    .eb-en_servicio     { background:#dcfce7; color:#166534; }
    .eb-finalizado      { background:#f1f5f9; color:#334155; }
    .eb-ausente         { background:#fee2e2; color:#991b1b; }
    .eb-cancelado       { background:#f1f5f9; color:#9ca3af; }

    /* ── Paginación ── */
    .pagination-wrap {
        display:flex; align-items:center; justify-content:space-between;
        padding:12px 18px; border-top:1px solid #e2e8f0; flex-wrap:wrap; gap:8px;
    }
    .pagination-info { font-size:.78rem; color:#64748b; }
    .page-btns { display:flex; gap:4px; }
    .page-btns button { font-size:.78rem; padding:3px 10px; border-radius:6px;
                        border:1px solid #e2e8f0; background:#fff; cursor:pointer; }
    .page-btns button.active { background:var(--brand,#2563eb); color:#fff; border-color:var(--brand,#2563eb); }
    .page-btns button:disabled { opacity:.4; cursor:default; }

    /* ── Estado vacío ── */
    .empty-state { text-align:center; color:#94a3b8; padding:60px 20px; font-size:.9rem; }
    .empty-state i { font-size:2.5rem; display:block; margin-bottom:10px; }

    /* ── Spinner ── */
    .spinner-row td { text-align:center; padding:40px; color:#94a3b8; }

    /* ── Detalle expandible ── */
    .detail-row { background:#f8fafc; }
    .detail-row td { padding:0 !important; }
    .detail-body { padding:10px 18px 14px; }
    .detail-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(160px,1fr)); gap:8px; }
    .detail-item { background:#fff; border:1px solid #e2e8f0; border-radius:8px; padding:8px 12px; }
    .detail-item .d-lbl { font-size:.67rem; text-transform:uppercase; letter-spacing:.07em; color:#94a3b8; }
    .detail-item .d-val { font-size:.85rem; font-weight:600; color:#1e293b; }

    /* ── Exámenes y comentarios ── */
    .detail-extra { margin-top:10px; padding-top:10px; border-top:1px solid #e2e8f0; }
    .detail-extra .d-lbl { font-size:.67rem; text-transform:uppercase; letter-spacing:.07em; color:#94a3b8; margin-bottom:5px; }
    .detail-comment { padding:5px 0; border-bottom:1px solid #f1f5f9; font-size:.82rem; }
    .detail-comment:last-child { border-bottom:none; }
    /* ── Origen de cada nota ── */
    .com-tipo { font-size:.62rem; font-weight:700; letter-spacing:.04em; padding:1px 7px;
                border-radius:10px; text-transform:uppercase; margin-right:6px; }
    .com-tipo.recepcion { background:#dbeafe; color:#1d4ed8; }
    .com-tipo.muestras  { background:#dcfce7; color:#15803d; }
    .com-tipo.general   { background:#fef3c7; color:#92400e; }


    /* ── Documentos firmados ── */
    .docs-section { margin-top:10px; padding-top:10px; border-top:1px solid #e2e8f0; }
    .traza { border-left:2px solid #e2e8f0; margin:2px 0 0 6px; padding-left:10px; }
    .traza-fila { display:flex; align-items:flex-start; gap:8px; padding:3px 0; font-size:.78rem; }
    .traza-hora { color:#94a3b8; font-variant-numeric:tabular-nums; min-width:42px; }
    .traza-ico { width:14px; text-align:center; margin-top:2px; font-size:.72rem; }
    .traza-txt { flex:1; color:#334155; }
    .traza-quien { color:#64748b; font-style:italic; }
    .traza-extra { color:#b45309; font-size:.74rem; margin-top:1px; }
    .traza-nota { color:#94a3b8; font-size:.7rem; margin-top:6px; font-style:italic; }
    .docs-lbl { font-size:.65rem; font-weight:700; text-transform:uppercase; letter-spacing:.07em; color:#94a3b8; margin-bottom:5px; }
    .doc-pill { display:inline-flex; align-items:center; gap:4px; padding:3px 10px; border-radius:99px;
                font-size:.73rem; font-weight:600; margin:2px 2px; text-decoration:none; transition:opacity .15s; }
    .doc-pill:hover { opacity:.8; }
    .doc-pill.firmado  { background:#dcfce7; color:#166534; border:1px solid #bbf7d0; }
    .doc-pill.enviado  { background:#fef9c3; color:#78350f; border:1px solid #fde68a; }
    .doc-pill.pendiente{ background:#f1f5f9; color:#64748b; border:1px solid #e2e8f0; }
    .docs-empty { font-size:.78rem; color:#94a3b8; font-style:italic; }

    /* ── Modal cambio de estado ── */
    .estado-modal-backdrop {
        position:fixed; inset:0; background:rgba(0,0,0,.45); z-index:1050;
        display:flex; align-items:center; justify-content:center;
    }
    .estado-modal {
        background:#fff; border-radius:14px; padding:24px 28px; width:340px;
        box-shadow:0 20px 60px rgba(0,0,0,.2);
    }
    .estado-modal h5 { font-size:.95rem; font-weight:700; margin-bottom:4px; }
    .estado-modal .sub { font-size:.78rem; color:#64748b; margin-bottom:16px; }
    .estado-modal select { width:100%; padding:8px 10px; border:1px solid #e2e8f0;
                           border-radius:8px; font-size:.85rem; margin-bottom:16px; }
    .estado-modal .actions { display:flex; gap:8px; justify-content:flex-end; }

    /* ── Modal documento firmado ── */
    .doc-modal-backdrop {
        position:fixed; inset:0; background:rgba(0,0,0,.55); z-index:1060;
        display:flex; align-items:center; justify-content:center; padding:20px;
    }
    .doc-modal { background:#fff; border-radius:12px; width:100%; max-width:820px; height:88vh;
                 display:flex; flex-direction:column; overflow:hidden; box-shadow:0 20px 60px rgba(0,0,0,.25); }
    .doc-modal-head { display:flex; align-items:center; gap:10px; padding:12px 16px; border-bottom:1px solid #e2e8f0; }
    .doc-modal-head h5 { font-size:.9rem; font-weight:700; margin:0; flex:1; }
    .doc-modal-head button { border:none; background:none; font-size:1.1rem; color:#64748b; cursor:pointer; }
    .doc-modal iframe { flex:1; border:none; width:100%; }
</style>

<!-- ── Encabezado ────────────────────────────────────────────── -->
<div class="page-header">
    <a href="<?= BASE_URL ?>erp.php?m=turnero&v=dashboard" class="text-muted text-decoration-none small">
        <i class="fas fa-arrow-left me-1"></i>Dashboard
    </a>
    <h1><i class="fas fa-history me-2 text-primary"></i>Historial de Turnos</h1>
    <button class="btn btn-outline-success btn-sm" id="btnExport" title="Exportar CSV">
        <i class="fas fa-file-csv me-1"></i>Exportar CSV
    </button>
</div>

<!-- ── Barra de filtros ──────────────────────────────────────── -->
<div class="filter-bar">
    <div class="filter-group">
        <label>Desde</label>
        <input type="date" id="fDesde" class="form-control form-control-sm">
    </div>
    <div class="filter-group">
        <label>Hasta</label>
        <input type="date" id="fHasta" class="form-control form-control-sm">
    </div>
    <div class="filter-group">
        <label>Estado</label>
        <select id="fEstado" class="form-select form-select-sm">
            <option value="">Todos</option>
            <option value="finalizado">Finalizado</option>
            <option value="ausente">Ausente</option>
            <option value="cancelado">Cancelado</option>
            <option value="en_servicio">En servicio</option>
            <option value="en_espera_lugar">Esp. lugar</option>
            <option value="en_recepcion">En recepción</option>
            <option value="espera">En espera</option>
        </select>
    </div>
    <div class="filter-group" id="wrapLugar">
        <label>Lugar</label>
        <select id="fLugar" class="form-select form-select-sm">
            <option value="0">Todos</option>
        </select>
    </div>
    <div class="filter-group" id="wrapPrioridad">
        <label>Prioridad</label>
        <select id="fPrioridad" class="form-select form-select-sm">
            <option value="0">Todas</option>
        </select>
    </div>
    <div class="filter-group wide">
        <label>Buscar paciente / código</label>
        <input type="text" id="fQ" class="form-control form-control-sm" placeholder="Nombre o código…">
    </div>
    <button class="btn btn-primary btn-sm align-self-end" id="btnBuscar">
        <i class="fas fa-search me-1"></i>Buscar
    </button>
    <button class="btn btn-outline-secondary btn-sm align-self-end" id="btnHoy" title="Solo hoy">
        Hoy
    </button>
    <button class="btn btn-outline-secondary btn-sm align-self-end" id="btn7d" title="Últimos 7 días">
        7 días
    </button>
    <button class="btn btn-outline-secondary btn-sm align-self-end" id="btn30d" title="Últimos 30 días">
        30 días
    </button>
</div>

<!-- ── Contenido ──────────────────────────────────────────────── -->
<div class="content-wrap">

    <!-- Resumen por estado del rango -->
    <div class="kpi-strip" id="kpiStrip" style="display:none"></div>

    <!-- Tabla principal -->
    <div class="section-card">
        <div class="table-responsive">
            <table class="table table-hover align-middle" id="tablaHistorial">
                <thead>
                    <tr>
                        <th>Fecha</th>
                        <th>Código</th>
                        <th>Prioridad</th>
                        <th>Paciente</th>
                        <th>Recepción</th>
                        <th>Lugar / Bacteriólogo</th>
                        <th>Exámenes</th>
                        <th>Estado</th>
                        <th>Espera</th>
                        <th>Servicio</th>
                        <th>Total</th>
                        <th></th>
                    </tr>
                </thead>
                <tbody id="tbody">
                    <tr class="spinner-row">
                        <td colspan="11"><i class="fas fa-spinner fa-spin me-2"></i>Cargando…</td>
                    </tr>
                </tbody>
            </table>
        </div>

        <!-- Paginación -->
        <div class="pagination-wrap" id="paginacionWrap" style="display:none">
            <div class="pagination-info" id="paginacionInfo"></div>
            <div class="page-btns" id="pagBtns"></div>
        </div>
    </div>
</div>

<script>
/* ═══════════════════════════════════════════════════════════
   Historial de Turnos
   ═══════════════════════════════════════════════════════════ */
const API = '<?= BASE_URL ?>modules/turnero/api/';
const SERVICIO_PROLONGADO_MIN = 20; // minutos — a partir de aquí se resalta en rojo

let _state = {
    fechaDesde : '',
    fechaHasta : '',
    estado     : '',
    lugarId    : 0,
    prioridadId: 0,
    q          : '',
    page       : 1,
    perPage    : 50,
    totalPages : 1,
    total      : 0,
};

// ── Utilidades ────────────────────────────────────────────────
const esc = s => (s == null ? '' : String(s))
    .replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;')
    .replace(/"/g,'&quot;').replace(/'/g,'&#39;').replace(/`/g,'&#96;');

function hoy()  { return new Date().toISOString().slice(0,10); }
function hace(n){ return new Date(Date.now()-n*86400000).toISOString().slice(0,10); }

// ── Inicialización ────────────────────────────────────────────
document.addEventListener('DOMContentLoaded', async () => {
    // Fecha por defecto: hoy
    document.getElementById('fDesde').value  = hoy();
    document.getElementById('fHasta').value  = hoy();
    document.getElementById('fHasta').max    = hoy();

    // Cargar catálogos (lugares + prioridades)
    await cargarMeta();

    // Primera carga
    buscar();

    // Eventos
    document.getElementById('btnBuscar').addEventListener('click', buscar);
    document.getElementById('fQ').addEventListener('keydown', e => { if (e.key==='Enter') buscar(); });
    document.getElementById('btnExport').addEventListener('click', exportarCSV);

    document.getElementById('btnHoy').addEventListener('click', () => {
        document.getElementById('fDesde').value = hoy();
        document.getElementById('fHasta').value = hoy();
        buscar();
    });
    document.getElementById('btn7d').addEventListener('click', () => {
        document.getElementById('fDesde').value = hace(6);
        document.getElementById('fHasta').value = hoy();
        buscar();
    });
    document.getElementById('btn30d').addEventListener('click', () => {
        document.getElementById('fDesde').value = hace(29);
        document.getElementById('fHasta').value = hoy();
        buscar();
    });
});

// ── Catálogos ─────────────────────────────────────────────────
async function cargarMeta() {
    try {
        const res  = await fetch(`${API}get_historial.php?meta=1&fecha_desde=${hoy()}&fecha_hasta=${hoy()}&per_page=1`);
        const json = await res.json();
        if (!json.ok) return;

        const selLugar = document.getElementById('fLugar');
        (json.meta.lugares || []).forEach(l => {
            const o = document.createElement('option');
            o.value = l.id; o.textContent = l.nombre;
            selLugar.appendChild(o);
        });

        const selPri = document.getElementById('fPrioridad');
        (json.meta.prioridades || []).forEach(p => {
            const o = document.createElement('option');
            o.value = p.id;
            o.textContent = `${p.codigo} — ${p.nombre}`;
            selPri.appendChild(o);
        });
    } catch(_) {}
}

// ── Búsqueda principal ────────────────────────────────────────
function buscar(pageNum) {
    _state.fechaDesde  = document.getElementById('fDesde').value     || hace(6);
    _state.fechaHasta  = document.getElementById('fHasta').value     || hoy();
    _state.estado      = document.getElementById('fEstado').value;
    _state.lugarId     = parseInt(document.getElementById('fLugar').value)    || 0;
    _state.prioridadId = parseInt(document.getElementById('fPrioridad').value)|| 0;
    _state.q           = document.getElementById('fQ').value.trim();
    _state.page        = pageNum || 1;

    cargarPagina();
}

function irATurno(codigo, fecha) {
    document.getElementById('fDesde').value = fecha || hoy();
    document.getElementById('fHasta').value = fecha || hoy();
    document.getElementById('fQ').value     = codigo;
    document.getElementById('fEstado').value = '';
    buscar();
    window.scrollTo({top:0, behavior:'smooth'});
}

async function cargarPagina() {
    mostrarSpinner();
    const params = new URLSearchParams({
        fecha_desde  : _state.fechaDesde,
        fecha_hasta  : _state.fechaHasta,
        estado       : _state.estado,
        lugar_id     : _state.lugarId,
        prioridad_id : _state.prioridadId,
        q            : _state.q,
        page         : _state.page,
        per_page     : _state.perPage,
    });

    try {
        const res  = await fetch(`${API}get_historial.php?${params}`);
        const json = await res.json();
        if (!json.ok) { mostrarError(json.error || 'Error al cargar historial'); return; }

        _state.totalPages = json.total_pages;
        _state.total      = json.total;
        _state.page       = json.page;

        renderKpis(json.resumen_estados);
        renderTabla(json.turnos);
        renderPaginacion();
    } catch(e) {
        mostrarError('Error de conexión');
    }
}

// ── KPIs de resumen ───────────────────────────────────────────
const ESTADO_META = {
    finalizado      : { lbl:'Finalizados',    bg:'#f1f5f9', color:'#334155' },
    ausente         : { lbl:'Ausentes',       bg:'#fee2e2', color:'#991b1b' },
    cancelado       : { lbl:'Cancelados',     bg:'#f1f5f9', color:'#9ca3af' },
    en_servicio     : { lbl:'En servicio',    bg:'#dcfce7', color:'#166534' },
    en_espera_lugar : { lbl:'Esp. lugar',     bg:'#fde68a', color:'#92400e' },
    en_recepcion    : { lbl:'En recepción',   bg:'#dbeafe', color:'#1e40af' },
    espera          : { lbl:'En espera',      bg:'#fef9c3', color:'#78350f' },
};

function renderKpis(resumen) {
    const strip = document.getElementById('kpiStrip');
    let total = Object.values(resumen).reduce((a,b)=>a+(+b),0);
    if (!total) { strip.style.display='none'; return; }

    strip.style.display = 'flex';
    strip.innerHTML = `
        <div class="kpi-chip">
            <span class="chip-val">${total}</span>
            <span class="chip-lbl">turnos (rango)</span>
        </div>
        ${Object.entries(resumen).map(([est,cnt]) => {
            const m = ESTADO_META[est] || {lbl:est, bg:'#f1f5f9', color:'#334155'};
            return `<div class="kpi-chip" style="border-color:${m.color}22">
                <span class="chip-val" style="color:${m.color}">${cnt}</span>
                <span class="chip-lbl">${m.lbl}</span>
            </div>`;
        }).join('')}
    `;
}

// ── Tabla ─────────────────────────────────────────────────────
const ESTADO_CLS = {
    espera:'eb-espera', en_recepcion:'eb-en_recepcion', en_espera_lugar:'eb-en_espera_lugar',
    en_servicio:'eb-en_servicio', finalizado:'eb-finalizado', ausente:'eb-ausente', cancelado:'eb-cancelado',
};
const ESTADO_LBL = {
    espera:'Espera', en_recepcion:'Recepción', en_espera_lugar:'Esp. lugar',
    en_servicio:'En servicio', finalizado:'Finalizado', ausente:'Ausente', cancelado:'Cancelado',
};

function renderTabla(turnos) {
    const tbody = document.getElementById('tbody');
    if (!turnos.length) {
        tbody.innerHTML = `<tr><td colspan="12">
            <div class="empty-state"><i class="fas fa-search"></i>Sin resultados para los filtros aplicados</div>
        </td></tr>`;
        return;
    }

    tbody.innerHTML = turnos.map((t,i) => {
        const nombreBd     = esc(t.paciente_bd     || '');
        const nombreKiosko = esc(t.paciente_nombre || '');
        const nombre       = nombreBd || nombreKiosko || '—';
        const docBd        = t.paciente_doc ? esc((t.paciente_tipo_doc || 'CC') + ' ' + t.paciente_doc) : '';
        const lugar   = esc(t.lugar_nombre || '—');
        const fecha   = t.fecha_sesion || '—';
        const horaEnt = t.creado_at
            ? new Date(t.creado_at.replace(' ','T'))
                .toLocaleString('es-CO',{hour:'2-digit',minute:'2-digit'})
            : '—';
        const espMin  = t.espera_min    != null ? t.espera_min    + ' m' : '—';
        const esProlongado = t.servicio_min != null && t.servicio_min > SERVICIO_PROLONGADO_MIN;
        const srvMin  = t.servicio_min  != null
            ? `<span${esProlongado ? ' style="color:#dc2626;font-weight:700" title="Servicio prolongado"' : ''}>${esProlongado ? '<i class="fas fa-exclamation-triangle me-1" style="font-size:.7rem"></i>' : ''}${t.servicio_min} m</span>`
            : '—';
        const totMin  = t.total_min     != null ? t.total_min     + ' m' : '—';
        const tel     = esc(t.paciente_cel || '—');
        const priCls  = esc(t.prioridad_color || '#888');
        const cls     = ESTADO_CLS[t.estado] || 'eb-finalizado';
        const lbl     = ESTADO_LBL[t.estado] || t.estado;
        const rowId   = `det-${t.id}`;

        // Recepción: desk + recepcionista
        const desk     = esc(t.recepcion_desk_nombre || '—');
        const recep    = esc(t.atendido_recepcion_nombre || '—');
        const bacterio = esc(t.atendido_lugar_nombre || '—');

        // Exámenes: badges con código
        // Solo el conteo: con 9,5 exámenes de promedio por turno, las etiquetas de
        // código llenaban cinco renglones y la tabla quedaba ilegible. Los nombres
        // completos ya están en el detalle desplegable, así que no se pierde nada.
        const nExam = (t.examenes && t.examenes.length) ? t.examenes.length : 0;
        const examsHtml = nExam
            ? `<span class="badge bg-success-subtle text-success" style="font-size:.68rem"
                     title="${esc(t.examenes.map(e => e.nombre || e.codigo).join(' · '))}">
                   ${nExam} examen${nExam === 1 ? '' : 'es'}
               </span>`
            : '<span class="text-muted small">—</span>';

        return `<tr data-id="${t.id}" style="cursor:pointer"
                    onclick="filaDetalle(event, '${rowId}', ${t.id})">
            <td class="text-nowrap text-muted small">${esc(fecha)}</td>
            <td><strong style="color:${priCls}">${esc(t.codigo)}</strong></td>
            <td>
                <span class="eb" style="background:${priCls}22;color:${priCls}">
                    ${esc(t.prioridad_codigo)}
                </span>
            </td>
            <td>
                <div>${nombre}${docBd ? `<span class="text-muted" style="font-size:.7rem;margin-left:5px">${docBd}</span>` : ''}</div>
                ${nombreKiosko ? `<div class="text-muted" style="font-size:.72rem">Kiosko: ${nombreKiosko}</div>` : ''}
            </td>
            <td class="small">
                <div class="text-muted" style="font-size:.72rem"><i class="fas fa-desktop me-1 opacity-50"></i>${desk}</div>
                <div><i class="fas fa-user-tie me-1 opacity-50" style="font-size:.72rem"></i>${recep}</div>
            </td>
            <td class="small">
                <div class="fw-semibold">${lugar}</div>
                <div class="text-muted" style="font-size:.72rem"><i class="fas fa-microscope me-1 opacity-50"></i>${bacterio}</div>
            </td>
            <td class="text-nowrap">${examsHtml}</td>
            <td><span class="eb ${cls}">${lbl}</span></td>
            <td class="text-nowrap">${espMin}</td>
            <td class="text-nowrap">${srvMin}</td>
            <td class="text-nowrap">${totMin}</td>
            <td class="text-nowrap">
                <button class="btn btn-sm btn-outline-secondary py-0 px-2 me-1"
                        onclick="event.stopPropagation();toggleDetalle('${rowId}', this, ${t.id})"
                        title="Ver detalles">
                    <i class="fas fa-chevron-down" style="font-size:.65rem"></i>
                </button>
                <button class="btn btn-sm btn-outline-warning py-0 px-2"
                        onclick="event.stopPropagation();abrirModalEstado(${t.id}, '${t.estado}', '${nombre}')"
                        title="Cambiar estado">
                    <i class="fas fa-exchange-alt" style="font-size:.65rem"></i>
                </button>
            </td>
        </tr>
        <tr id="${rowId}" class="detail-row" style="display:none">
            <td colspan="11">
                <div class="detail-body">
                    ${renderDetalle(t)}
                </div>
            </td>
        </tr>`;
    }).join('');
}

function renderDetalle(t) {
    const fmt = dt => {
        if (!dt) return '—';
        const d = new Date(dt.replace(' ','T'));
        return d.toLocaleString('es-CO',{dateStyle:'short',timeStyle:'short'});
    };
    const items = [
        { lbl:'Creado',              val: fmt(t.creado_at) },
        { lbl:'Inicio recepción',    val: fmt(t.inicio_recepcion_at) },
        { lbl:'Fin recepción',       val: fmt(t.fin_recepcion_at) },
        { lbl:'Inicio servicio',     val: fmt(t.inicio_lugar_at) },
        { lbl:'Fin servicio',        val: fmt(t.fin_lugar_at) },
        { lbl:'Código completo',     val: esc(t.codigo) },
        { lbl:'Número en cola',      val: t.numero ?? '—' },
        { lbl:'Teléfono',            val: esc(t.paciente_cel || '—') },
        { lbl:'Recepción (desk)',     val: esc(t.recepcion_desk_nombre || '—') },
        { lbl:'Atendió recepción',   val: esc(t.atendido_recepcion_nombre || '—') },
        { lbl:'Atendió muestras',    val: esc(t.atendido_lugar_nombre || '—') },
        { lbl:'Notas',               val: esc(t.notas || '—') },
    ];
    // Turnos vinculados (muestra pendiente completada en otra visita, o viceversa)
    let relHtml = '';
    if (t.relacionados && t.relacionados.length) {
        relHtml = `<div class="detail-extra">
            <div class="d-lbl"><i class="fas fa-link me-1 text-primary"></i>Turno vinculado</div>
            <div class="d-val">${t.relacionados.map(r => {
                const txt = r.direccion === 'seguimiento'
                    ? `Muestra completada en ${esc(r.codigo)}`
                    : `Completa muestra pendiente de ${esc(r.codigo)}`;
                return `<button class="btn btn-sm btn-outline-primary py-0 px-2 mb-1 me-1"
                            style="font-size:.72rem" onclick="irATurno('${esc(r.codigo)}','${r.fecha}')">
                        <i class="fas fa-arrow-right me-1"></i>${txt}
                    </button>`;
            }).join('')}</div>
        </div>`;
    }

    // Exámenes
    let examHtml = '';
    if (t.examenes && t.examenes.length) {
        examHtml = `<div class="detail-extra">
            <div class="d-lbl"><i class="fas fa-vials me-1 text-success"></i>Exámenes (${t.examenes.length})</div>
            <div class="d-val">${t.examenes.map(e => `<span class="badge bg-success-subtle text-success me-1 mb-1">${esc(e.nombre)}</span>`).join('')}</div>
        </div>`;
    }

    // Comentarios
    let comHtml = '';
    if (t.comentarios && t.comentarios.length) {
        comHtml = `<div class="detail-extra">
            <div class="d-lbl"><i class="fas fa-comments me-1 text-primary"></i>Notas y observaciones (${t.comentarios.length})</div>
            <div>${t.comentarios.map(c => `
                <div class="detail-comment">
                    <span class="com-tipo ${esc(c.tipo||'general')}">${({recepcion:'Recepción',muestras:'Toma de muestras',general:'General'})[c.tipo]||c.tipo}</span>
                    <span class="fw-semibold">${esc(c.usuario_nombre)}</span>
                    <span class="text-muted small ms-1">${c.creado_at ? new Date(c.creado_at.replace(' ','T')).toLocaleString('es-CO',{dateStyle:'short',timeStyle:'short'}) : ''}</span>
                    <div class="text-secondary">${esc(c.comentario)}</div>
                </div>`).join('')}
            </div>
        </div>`;
    }

    return `<div class="detail-grid">
        ${items.map(it=>`
            <div class="detail-item">
                <div class="d-lbl">${it.lbl}</div>
                <div class="d-val">${it.val}</div>
            </div>`).join('')}
    </div>
    ${relHtml}${examHtml}${comHtml}
    <div class="docs-section" id="traza-${t.id}">
        <div class="docs-lbl"><i class="fas fa-clock-rotate-left me-1"></i>Qué pasó con este turno</div>
        <span class="text-muted small"><i class="fas fa-spinner fa-spin me-1"></i>Cargando…</span>
    </div>
    <div class="docs-section" id="docs-${t.id}">
        <div class="docs-lbl"><i class="fas fa-file-signature me-1"></i>Documentos</div>
        <span class="text-muted small"><i class="fas fa-spinner fa-spin me-1"></i>Cargando…</span>
    </div>`;
}

/**
 * Clic en cualquier parte de la fila: abre o cierra su detalle.
 *
 * Se ignora si el usuario estaba seleccionando texto —copiar un documento o un
 * nombre es frecuente aquí y sería molesto que la fila se abriera al soltar— y
 * si el clic cayó sobre un enlace o un botón, que tienen lo suyo que hacer.
 */
function filaDetalle(ev, rowId, turnoId) {
    if (ev.target.closest('button, a, input, select')) return;
    const sel = window.getSelection();
    if (sel && sel.toString().length > 0) return;
    const fila = document.querySelector(`tr[data-id="${turnoId}"]`);
    const btn  = fila ? fila.querySelector('button[title="Ver detalles"]') : null;
    if (btn) toggleDetalle(rowId, btn, turnoId);
}

function toggleDetalle(rowId, btn, turnoId) {
    const row = document.getElementById(rowId);
    const icon = btn.querySelector('i');
    if (!row) return;
    const visible = row.style.display !== 'none';
    row.style.display = visible ? 'none' : '';
    icon.className = visible ? 'fas fa-chevron-down' : 'fas fa-chevron-up';
    icon.style.fontSize = '.65rem';
    if (!visible && turnoId) {
        const docsEl = document.getElementById(`docs-${turnoId}`);
        if (docsEl && !docsEl.dataset.loaded) {
            docsEl.dataset.loaded = '1';
            cargarDocumentosTurno(turnoId, docsEl);
        }
        const trazaEl = document.getElementById(`traza-${turnoId}`);
        if (trazaEl && !trazaEl.dataset.loaded) {
            trazaEl.dataset.loaded = '1';
            cargarTrazaTurno(turnoId, trazaEl);
        }
    }
}

const BASE_URL_ROOT = '<?= BASE_URL ?>';

// ── Bitácora del turno ────────────────────────────────────────
// Junta en una sola línea de tiempo lo que antes estaba repartido: el recorrido
// del turno, los documentos, los comentarios del personal, las muestras y las
// acciones administrativas auditadas.
const TRAZA_ICONO = {
    turno:'fa-plus-circle',      llamado:'fa-bullhorn',   atencion:'fa-user-check',
    muestra:'fa-vial',           fin:'fa-flag-checkered', doc:'fa-paper-plane',
    doc_ok:'fa-file-signature',  comentario:'fa-comment', alerta:'fa-triangle-exclamation',
    admin:'fa-user-shield',
};
const TRAZA_COLOR = {
    alerta:'#dc2626', doc_ok:'#16a34a', comentario:'#2563eb',
    fin:'#0f766e',    admin:'#7c3aed',
};

async function cargarTrazaTurno(turnoId, container) {
    const titulo = '<div class="docs-lbl"><i class="fas fa-clock-rotate-left me-1"></i>Qué pasó con este turno</div>';
    try {
        const res  = await fetch(`${API}get_traza_turno.php?turno_id=${turnoId}`);
        const json = await res.json();
        if (!json.ok) { container.innerHTML = titulo + '<span class="docs-empty">No se pudo cargar</span>'; return; }

        const ev = json.eventos || [];
        if (!ev.length) { container.innerHTML = titulo + '<span class="docs-empty">Sin registros</span>'; return; }

        const hora = c => c ? new Date(c.replace(' ','T')).toLocaleTimeString('es-CO',{hour:'2-digit',minute:'2-digit'}) : '';
        const filas = ev.map(e => {
            const color = TRAZA_COLOR[e.tipo] || '#94a3b8';
            const ico   = TRAZA_ICONO[e.tipo] || 'fa-circle';
            const quien = e.quien ? `<span class="traza-quien">${esc(e.quien)}</span>` : '';
            const extra = e.extra ? `<div class="traza-extra">${esc(e.extra)}</div>` : '';
            return `<div class="traza-fila">
                <span class="traza-hora">${hora(e.cuando)}</span>
                <i class="fas ${ico} traza-ico" style="color:${color}"></i>
                <div class="traza-txt"><span>${esc(e.texto)}</span> ${quien}${extra}</div>
            </div>`;
        }).join('');

        // El chat no se vuelca aquí: son datos personales del paciente y esta es
        // una pantalla de consulta. Se indica que existe y se enlaza.
        const chat = json.chat
            ? `<div class="traza-fila">
                   <span class="traza-hora"></span>
                   <i class="fab fa-whatsapp traza-ico" style="color:#25d366"></i>
                   <div class="traza-txt">
                       <a href="erp.php?m=turnero&v=chat&user_id=${json.chat.user_id}" target="_blank">
                           ${json.chat.mensajes} mensaje(s) de WhatsApp ese día — ver conversación
                       </a>
                   </div>
               </div>` : '';

        // Se dice qué NO quedó registrado, para que la ausencia de un evento no
        // se lea como prueba de que no ocurrió.
        const nota = (json.sinRastro && json.sinRastro.length)
            ? `<div class="traza-nota">El sistema aún no deja rastro de: ${json.sinRastro.map(esc).join(' · ')}.</div>`
            : '';

        container.innerHTML = titulo + `<div class="traza">${filas}${chat}</div>` + nota;
    } catch (_) {
        container.innerHTML = titulo + '<span class="docs-empty">Error al cargar</span>';
    }
}

async function cargarDocumentosTurno(turnoId, container) {
    try {
        const res  = await fetch(`${API}get_consentimientos.php?turno_id=${turnoId}`);
        const json = await res.json();
        if (!json.ok) { container.querySelector('span').textContent = 'Error al cargar'; return; }
        const list = json.consentimientos || [];
        if (!list.length) {
            container.innerHTML = '<div class="docs-lbl"><i class="fas fa-file-signature me-1"></i>Documentos</div>'
                + '<span class="docs-empty">Sin documentos para este turno</span>';
            return;
        }
        const LBLS = { firmado:'Firmado', enviado:'Enviado', visto:'Visto', pendiente:'Pendiente' };
        const pills = list.map(c => {
            const est    = c.estado || 'pendiente';
            const nombre = esc(c.formulario_nombre || 'Documento');
            // Formulario de tomas progresivas (ej. Control de Tomas de Muestras Prolongadas F-LAB-28)
            const tomas  = c.es_toma_progresiva
                ? ` <span class="badge bg-danger-subtle text-danger ms-1" style="font-size:.62rem">${c.tomas_firmadas||0}/${c.tomas_total||0} tomas</span>`
                : '';
            if (est === 'firmado' && c.token) {
                // Mismos parámetros que bandeja: compact activa la grilla de campos
                // y las tarjetas de toma; sin ellos el documento se ve en lista larga.
                const url = BASE_URL_ROOT + 'ver_formulario_enviado.php?token=' + encodeURIComponent(c.token) + '&embed=1&compact=1&zoom=1.1';
                return `<a class="doc-pill firmado" href="${url}" onclick="return abrirDocModal(event,'${url}','${nombre.replace(/'/g,"\\'")}')">
                    <i class="fas fa-check-circle"></i>${nombre}${tomas}
                </a>`;
            }
            const cls = est === 'enviado' || est === 'visto' ? 'enviado' : 'pendiente';
            const ico = est === 'enviado' ? 'fa-paper-plane' : (est === 'visto' ? 'fa-eye' : 'fa-clock');
            return `<span class="doc-pill ${cls}"><i class="fas ${ico}"></i>${nombre}${tomas}</span>`;
        }).join('');

        // Detalle por toma (quién atendió cada una) para formularios de tomas progresivas
        const detalles = list.filter(c => c.es_toma_progresiva && c.tomas_detalle && c.tomas_detalle.length)
            .map(c => `<table class="table table-sm mb-2" style="font-size:.76rem">
                <thead><tr><th>${esc(c.formulario_nombre||'')}</th><th>Hora</th><th>Atendió</th></tr></thead>
                <tbody>${c.tomas_detalle.map(t => `<tr class="${t.firmado ? '' : 'text-muted'}">
                    <td>${esc((t.label||'').replace(/^Toma\s*·\s*/,''))}</td>
                    <td>${esc(t.hora || '—')}</td>
                    <td>${t.firmado ? esc(t.firmante || '—') : '<i class="fas fa-clock"></i> pendiente'}</td>
                </tr>`).join('')}</tbody>
            </table>`).join('');

        container.innerHTML = '<div class="docs-lbl"><i class="fas fa-file-signature me-1"></i>Documentos</div>' + pills + detalles;
    } catch(_) {
        const sp = container.querySelector('span');
        if (sp) sp.textContent = 'Error de conexión';
    }
}

// ── Paginación ────────────────────────────────────────────────
function renderPaginacion() {
    const wrap = document.getElementById('paginacionWrap');
    const info = document.getElementById('paginacionInfo');
    const btns = document.getElementById('pagBtns');

    wrap.style.display = '';

    const desde = (_state.page - 1) * _state.perPage + 1;
    const hasta = Math.min(_state.page * _state.perPage, _state.total);
    info.textContent = `Mostrando ${desde}–${hasta} de ${_state.total} turnos`;

    // Generar botones de página (máximo 7 visibles)
    const total   = _state.totalPages;
    const current = _state.page;
    let pages     = [];

    if (total <= 7) {
        pages = Array.from({length: total}, (_,i) => i+1);
    } else {
        pages = [1];
        if (current > 3)             pages.push('…');
        for (let p = Math.max(2, current-1); p <= Math.min(total-1, current+1); p++) pages.push(p);
        if (current < total-2)       pages.push('…');
        pages.push(total);
    }

    btns.innerHTML = `
        <button ${current<=1?'disabled':''} onclick="irPagina(${current-1})">
            <i class="fas fa-chevron-left"></i>
        </button>
        ${pages.map(p =>
            p === '…'
            ? `<button disabled>…</button>`
            : `<button class="${p===current?'active':''}" onclick="irPagina(${p})">${p}</button>`
        ).join('')}
        <button ${current>=total?'disabled':''} onclick="irPagina(${current+1})">
            <i class="fas fa-chevron-right"></i>
        </button>
    `;
}

function irPagina(n) {
    if (n < 1 || n > _state.totalPages) return;
    _state.page = n;
    cargarPagina();
    window.scrollTo({top:0, behavior:'smooth'});
}

// ── Exportar CSV ──────────────────────────────────────────────
function exportarCSV() {
    const params = new URLSearchParams({
        fecha    : _state.fechaDesde,           // export_csv actual usa 'fecha' — usamos fecha_desde
        m        : 'historial',                 // flag para que export_csv sepa que es multi-día
        fecha_desde  : _state.fechaDesde,
        fecha_hasta  : _state.fechaHasta,
        estado       : _state.estado,
        lugar_id     : _state.lugarId,
        prioridad_id : _state.prioridadId,
        q            : _state.q,
        per_page     : 9999,
        page         : 1,
    });
    // Generamos CSV en cliente a partir de los datos actuales si son pocos,
    // o mandamos al endpoint get_historial con per_page alto para descarga
    window.open(`${API}export_historial.php?${params}`, '_blank');
}

// ── Cambio de estado ─────────────────────────────────────────
const ESTADOS_OPCIONES = {
    espera          : [{v:'en_recepcion',    l:'En recepción'}, {v:'ausente', l:'Ausente'}, {v:'cancelado', l:'Cancelado'}],
    en_recepcion    : [{v:'en_espera_lugar', l:'Esp. lugar'}, {v:'espera', l:'Espera'}, {v:'ausente', l:'Ausente'}, {v:'cancelado', l:'Cancelado'}],
    en_espera_lugar : [{v:'en_servicio',     l:'En servicio'}, {v:'ausente', l:'Ausente'}, {v:'cancelado', l:'Cancelado'}],
    en_servicio     : [{v:'finalizado',      l:'Finalizado'}, {v:'en_espera_lugar', l:'Esp. lugar'}, {v:'ausente', l:'Ausente'}, {v:'cancelado', l:'Cancelado'}],
    // estados finales: reapertura (admin)
    finalizado      : [{v:'en_servicio',     l:'Reabrir → En servicio'}, {v:'en_espera_lugar', l:'Reabrir → Esp. lugar'}, {v:'espera', l:'Reabrir → Espera'}],
    ausente         : [{v:'espera',          l:'Reabrir → Espera'}, {v:'en_servicio', l:'Reabrir → En servicio'}],
    cancelado       : [{v:'espera',          l:'Reabrir → Espera'}, {v:'en_servicio', l:'Reabrir → En servicio'}],
};

let _modalTurnoId = null;

function abrirModalEstado(turnoId, estadoActual, nombre) {
    _modalTurnoId = turnoId;
    const opciones = ESTADOS_OPCIONES[estadoActual] || [];
    if (!opciones.length) { alert('No hay transiciones disponibles para este estado.'); return; }

    const sel = opciones.map(o => `<option value="${o.v}">${o.l}</option>`).join('');
    const esReopetura = ['finalizado','ausente','cancelado'].includes(estadoActual);

    const backdrop = document.createElement('div');
    backdrop.className = 'estado-modal-backdrop';
    backdrop.id = 'estadoModalBackdrop';
    backdrop.innerHTML = `
        <div class="estado-modal" onclick="event.stopPropagation()">
            <h5><i class="fas fa-exchange-alt me-2 text-warning"></i>Cambiar estado del turno</h5>
            <div class="sub">${nombre}${esReopetura ? ' <span class="badge bg-warning text-dark ms-1">Reapertura admin</span>' : ''}</div>
            <select id="selectNuevoEstado">${sel}</select>
            <div class="actions">
                <button class="btn btn-sm btn-outline-secondary" onclick="cerrarModalEstado()">Cancelar</button>
                <button class="btn btn-sm btn-warning" onclick="confirmarCambioEstado()">
                    <i class="fas fa-check me-1"></i>Confirmar
                </button>
            </div>
        </div>`;
    backdrop.addEventListener('click', cerrarModalEstado);
    document.body.appendChild(backdrop);
}

function cerrarModalEstado() {
    document.getElementById('estadoModalBackdrop')?.remove();
    _modalTurnoId = null;
}

async function confirmarCambioEstado() {
    const nuevoEstado = document.getElementById('selectNuevoEstado').value;
    if (!_modalTurnoId || !nuevoEstado) return;

    const btn = document.querySelector('#estadoModalBackdrop .btn-warning');
    btn.disabled = true;
    btn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Guardando…';

    try {
        const res  = await fetch(`${API}cambiar_estado.php`, {
            method : 'POST',
            headers: { 'Content-Type': 'application/json' },
            body   : JSON.stringify({ turno_id: _modalTurnoId, nuevo_estado: nuevoEstado }),
        });
        const json = await res.json();
        if (json.ok) {
            cerrarModalEstado();
            buscar(_state.page);
        } else {
            alert('Error: ' + (json.error || 'No se pudo cambiar el estado.'));
            btn.disabled = false;
            btn.innerHTML = '<i class="fas fa-check me-1"></i>Confirmar';
        }
    } catch(e) {
        alert('Error de conexión');
        btn.disabled = false;
        btn.innerHTML = '<i class="fas fa-check me-1"></i>Confirmar';
    }
}

// ── Modal documento firmado ────────────────────────────────────
function abrirDocModal(ev, url, nombre) {
    ev.preventDefault();
    const backdrop = document.createElement('div');
    backdrop.className = 'doc-modal-backdrop';
    backdrop.id = 'docModalBackdrop';
    backdrop.innerHTML = `
        <div class="doc-modal" onclick="event.stopPropagation()">
            <div class="doc-modal-head">
                <h5><i class="fas fa-file-signature me-2 text-success"></i>${esc(nombre)}</h5>
                <a href="${url}" target="_blank" title="Abrir en pestaña nueva" class="me-2"><i class="fas fa-external-link-alt"></i></a>
                <button onclick="cerrarDocModal()" title="Cerrar"><i class="fas fa-times"></i></button>
            </div>
            <iframe src="${url}"></iframe>
        </div>`;
    backdrop.addEventListener('click', cerrarDocModal);
    document.body.appendChild(backdrop);
    return false;
}
function cerrarDocModal() {
    document.getElementById('docModalBackdrop')?.remove();
}

// ── Helpers visuales ──────────────────────────────────────────
function mostrarSpinner() {
    document.getElementById('tbody').innerHTML =
        '<tr class="spinner-row"><td colspan="11"><i class="fas fa-spinner fa-spin me-2"></i>Buscando…</td></tr>';
    document.getElementById('paginacionWrap').style.display = 'none';
    document.getElementById('kpiStrip').style.display = 'none';
}

function mostrarError(msg) {
    document.getElementById('tbody').innerHTML =
        `<tr><td colspan="11"><div class="empty-state text-danger">
            <i class="fas fa-exclamation-circle"></i>${esc(msg)}
        </div></td></tr>`;
}
</script>

<?php Layout::close(); ?>
