/**
 * Listado de asistentes por evento: check-in, búsqueda por código, exportación (Bootstrap Table + plugins CDN).
 */
(function (global) {
    'use strict';

    function $(sel, ctx) {
        return (ctx || document).querySelector(sel);
    }

    function textEscape(s) {
        if (s == null) {
            return '';
        }
        return String(s)
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#039;');
    }

    function readRoot() {
        return $('#rt-ev-attendees-root');
    }

    function postJson(url, csrf) {
        return fetch(url, {
            method: 'POST',
            headers: {
                Accept: 'application/json',
                'Content-Type': 'application/json',
                'X-CSRF-TOKEN': csrf,
                'X-Requested-With': 'XMLHttpRequest',
            },
            credentials: 'same-origin',
            body: '{}',
        }).then(function (r) {
            return r.json().then(function (body) {
                if (!r.ok) {
                    var msg = body.message || 'Error';
                    if (body.errors) {
                        var keys = Object.keys(body.errors);
                        if (keys.length && body.errors[keys[0]] && body.errors[keys[0]][0]) {
                            msg = body.errors[keys[0]][0];
                        }
                    }
                    var err = new Error(msg);
                    err.body = body;
                    err.status = r.status;
                    throw err;
                }
                return body;
            });
        });
    }

    function attendeeInfoFormatter(value, row) {
        var name = textEscape(row.holder_name || '—');
        var line = textEscape(row.attendee_ref_line || '');
        var resend = row.resend_tickets_url
            ? '<span class="text-muted mx-1">|</span><button type="button" class="btn btn-link btn-sm p-0 align-baseline text-nowrap rt-ev-btn-resend" title="Reenviar el correo con las entradas">Re-enviar entrada</button>'
            : '';
        return (
            '<div class="rt-ev-att-person text-left">' +
            '<div class="font-weight-bold text-dark mb-1">' +
            name +
            '</div>' +
            '<div class="small text-muted text-break mb-1">' +
            line +
            '</div>' +
            '<div class="small text-nowrap">' +
            '<button type="button" class="btn btn-link btn-sm p-0 align-baseline rt-ev-btn-detail" title="Ficha, datos de registro y QR">Registro</button>' +
            resend +
            '</div></div>'
        );
    }

    function orderStatusFormatter(value, row) {
        var st = row.order_status || '';
        var label = textEscape(row.order_status_label || '—');
        var cls = 'badge-light text-dark border';
        if (st === 'completed') {
            cls = 'badge-success';
        } else if (st === 'pending') {
            cls = 'badge-warning text-dark';
        } else if (st === 'refunded') {
            cls = 'badge-secondary';
        }
        return '<span class="badge ' + cls + '">' + label + '</span>';
    }

    function registroFormatter(value) {
        if (value == null || value === '' || value === '—') {
            return '<span class="text-muted">—</span>';
        }
        var s = String(value);
        if (s.length > 100) {
            return (
                '<span class="d-inline-block rt-ev-registro-extras" title="' +
                textEscape(s) +
                '">' +
                textEscape(s.slice(0, 97)) +
                '…</span>'
            );
        }
        return '<span class="text-break small">' + textEscape(s) + '</span>';
    }

    function statusFormatter(value, row) {
        if (row.checked_in) {
            return (
                '<span class="badge badge-success border-0 font-weight-bold">' +
                '<i class="bi bi-check-lg mr-1" aria-hidden="true"></i>' +
                textEscape('Ingresó') +
                '</span>'
            );
        }
        return (
            '<span class="badge badge-light text-dark border font-weight-bold">' +
            textEscape('Pendiente ingreso') +
            '</span>'
        );
    }

    function actionsFormatter(value, row) {
        var checked = row && !!row.checked_in;
        var html = [
            '<div class="btn-group btn-group-sm rt-dash-table-actions flex-wrap justify-content-center" role="group"',
            ' aria-label="Acciones por asistente">',
            '<button type="button" class="btn btn-sm btn-outline-primary rt-ev-btn-detail"',
            ' title="Ficha completa, datos de registro y código QR">',
            '<i class="bi bi-eye me-1" aria-hidden="true"></i>',
            '<span>Ver</span>',
            '</button>',
        ];
        if (!checked) {
            html.push(
                '<button type="button" class="btn btn-sm btn-success rt-ev-btn-checkin"',
                ' title="Marcar como persona que ya ingresó al evento">',
                '<i class="bi bi-check-lg me-1" aria-hidden="true"></i>',
                '<span>Ingresar</span>',
                '</button>'
            );
        } else {
            html.push(
                '<button type="button" class="btn btn-sm btn-outline-secondary rt-ev-btn-undo"',
                ' title="Quitar el registro de ingreso si fue por error">',
                '<i class="bi bi-arrow-counterclockwise me-1" aria-hidden="true"></i>',
                '<span>Anular</span>',
                '</button>'
            );
        }
        html.push('</div>');
        return html.join('');
    }

    function humanizeRegKey(key) {
        return String(key)
            .split(/[-_]/)
            .filter(Boolean)
            .map(function (w) {
                return w.charAt(0).toUpperCase() + w.slice(1).toLowerCase();
            })
            .join(' ');
    }

    function prettySpanishLabel(humanized) {
        var parts = String(humanized).split(/\s+/).filter(Boolean);
        if (!parts.length) {
            return '';
        }
        return parts
            .map(function (w, i) {
                if (i === 0) {
                    return w.charAt(0).toUpperCase() + w.slice(1).toLowerCase();
                }
                return w.toLowerCase();
            })
            .join(' ');
    }

    function regKeyCategory(key) {
        var s = String(key).toLowerCase();
        if (/acepto|reglamento|descargo|términos|terminos|política|politica|consentimiento|disclaimer/.test(s)) {
            return 'consent';
        }
        if (/emergencia|emergency/.test(s)) {
            return 'emergency';
        }
        return 'profile';
    }

    function displayLabelForRegKey(key) {
        var s = String(key).toLowerCase();
        if (/acepto|reglamento|descargo|términos|terminos|consentimiento|disclaimer/.test(s)) {
            return 'Reglamento y descargo de responsabilidad';
        }
        if (/emergencia|emergency/.test(s)) {
            return 'Nombre y teléfono';
        }
        return prettySpanishLabel(humanizeRegKey(key));
    }

    function isConsentKey(key) {
        var k = String(key || '').toLowerCase();
        return /acepto|reglamento|descargo|términos|terminos|consentimiento|disclaimer/.test(k);
    }

    function formatRegValue(val, key) {
        var k = key ? String(key).toLowerCase() : '';
        if (val == null || val === '') {
            return '—';
        }
        if (typeof val === 'boolean') {
            if (isConsentKey(key)) {
                return val ? 'Sí, aceptó' : 'No aceptó';
            }
            return val ? 'Sí' : 'No';
        }
        if (val === 1 || val === 0) {
            if (isConsentKey(key)) {
                return val === 1 ? 'Sí, aceptó' : 'No aceptó';
            }
        }
        if (val === '1' || val === '0') {
            if (isConsentKey(key)) {
                return val === '1' ? 'Sí, aceptó' : 'No aceptó';
            }
        }
        if (typeof val === 'string' && (val === 'true' || val === 'false') && isConsentKey(key)) {
            return val === 'true' ? 'Sí, aceptó' : 'No aceptó';
        }
        if (Array.isArray(val)) {
            return val.map(function (x) {
                return textEscape(String(x));
            }).join(', ');
        }
        if (typeof val === 'object') {
            try {
                return (
                    '<pre class="rt-ev-reg-json mb-0">' +
                    textEscape(JSON.stringify(val, null, 2)) +
                    '</pre>'
                );
            } catch (e) {
                return '—';
            }
        }
        var str = String(val);
        if (/\r?\n/.test(str)) {
            return str
                .split(/\r?\n/)
                .map(function (line) {
                    return textEscape(line);
                })
                .join('<br>');
        }
        return textEscape(str);
    }

    var REG_SECTION_ORDER = ['profile', 'emergency', 'consent'];
    var REG_SECTION_TITLE = {
        profile: 'Datos personales',
        emergency: 'Contacto de emergencia',
        consent: 'Avisos y aceptación',
    };

    function buildRegistrationBlock(row) {
        var rd = row.registration_data;
        if (!rd || typeof rd !== 'object' || Array.isArray(rd)) {
            return '';
        }
        var keys = Object.keys(rd);
        if (!keys.length) {
            return '';
        }
        var grouped = { profile: [], emergency: [], consent: [] };
        keys.forEach(function (k) {
            var v = rd[k];
            if (v === null || v === '') {
                return;
            }
            grouped[regKeyCategory(k)].push({ k: k, v: v });
        });

        var sectionsHtml = [];
        var first = true;
        REG_SECTION_ORDER.forEach(function (cat) {
            var items = grouped[cat];
            if (!items.length) {
                return;
            }
            var titleCls =
                'rt-ev-detail-reg-section-title small font-weight-bold text-uppercase text-muted' +
                (first ? ' mb-2' : ' mt-3 mb-2');
            first = false;
            var dlRows = items
                .map(function (item) {
                    return (
                        '<dt class="col-12 col-sm-5 text-muted mb-1">' +
                        textEscape(displayLabelForRegKey(item.k)) +
                        '</dt>' +
                        '<dd class="col-12 col-sm-7 mb-2 mb-sm-1 text-dark rt-ev-reg-dd">' +
                        formatRegValue(item.v, item.k) +
                        '</dd>'
                    );
                })
                .join('');
            sectionsHtml.push(
                '<div class="rt-ev-detail-reg-section">' +
                '<div class="' +
                titleCls +
                '">' +
                textEscape(REG_SECTION_TITLE[cat]) +
                '</div>' +
                '<dl class="row no-gutters mb-0 small">' +
                dlRows +
                '</dl></div>'
            );
        });

        if (!sectionsHtml.length) {
            return '';
        }
        return (
            '<div class="mt-3 pt-2 border-top">' +
            '<div class="small font-weight-bold text-uppercase text-muted mb-3">Datos de registro</div>' +
            '<div class="rt-ev-detail-reg rounded border bg-light px-3 py-3 small">' +
            sectionsHtml.join('') +
            '</div></div>'
        );
    }

    function openAttendeeDetail(row) {
        if (typeof Swal === 'undefined') {
            return;
        }
        var st = row.checked_in
            ? '<span class="badge badge-success">Ingresó</span>'
            : '<span class="badge badge-secondary">Pendiente de ingreso</span>';

        var html =
            '<div class="rt-ev-detail-swal text-start">' +
            '<div class="small text-muted mb-3 border-bottom pb-2">' +
            st +
            '</div>' +
            '<div class="row no-gutters">' +
            '<div class="col-md-7 pr-md-3">' +
            '<dl class="row no-gutters mb-0 small">' +
            '<dt class="col-12 col-sm-4 text-muted mb-1">Nombre</dt><dd class="col-12 col-sm-8 mb-2 font-weight-bold text-dark rt-ev-reg-dd">' +
            textEscape(row.holder_name || '—') +
            '</dd>' +
            '<dt class="col-12 col-sm-4 text-muted mb-1">Correo</dt><dd class="col-12 col-sm-8 mb-2 rt-ev-reg-dd">' +
            textEscape(row.holder_email || '—') +
            '</dd>' +
            '<dt class="col-12 col-sm-4 text-muted mb-1">Entrada</dt><dd class="col-12 col-sm-8 mb-2 rt-ev-reg-dd">' +
            textEscape(row.ticket_type || '—') +
            '</dd>' +
            '<dt class="col-12 col-sm-4 text-muted mb-1">Código de entrada</dt><dd class="col-12 col-sm-8 mb-2 rt-ev-reg-dd"><code class="small rt-ev-reg-code">' +
            textEscape(row.security_code || '—') +
            '</code></dd>' +
            '<dt class="col-12 col-sm-4 text-muted mb-1">Orden</dt><dd class="col-12 col-sm-8 mb-2 rt-ev-reg-dd">' +
            textEscape(row.order_label || '—') +
            ' <span class="text-muted">·</span> <span class="text-muted small">' +
            textEscape(row.order_uuid || '') +
            '</span></dd>' +
            '<dt class="col-12 col-sm-4 text-muted mb-1">Check-in</dt><dd class="col-12 col-sm-8 mb-2 rt-ev-reg-dd">' +
            textEscape(row.checked_in_at_label || '—') +
            '</dd>' +
            '<dt class="col-12 col-sm-4 text-muted mb-1">Registró ingreso</dt><dd class="col-12 col-sm-8 mb-2 rt-ev-reg-dd">' +
            textEscape(row.checked_in_by || '—') +
            '</dd>' +
            '</dl>' +
            buildRegistrationBlock(row) +
            '</div>' +
            '<div class="col-md-5 text-center pt-4 pt-md-0 pl-md-3 rt-ev-detail-qr-col">' +
            '<div class="small font-weight-bold text-uppercase text-muted mb-2">QR de entrada</div>' +
            '<div id="rt-ev-detail-qr" class="rt-ev-detail-qr-mount d-inline-block p-2 bg-white border rounded mx-auto"></div>' +
            '<p class="small text-muted mt-2 mb-0">Mismo código que en el correo de confirmación.</p>' +
            '</div>' +
            '</div>' +
            '</div>';

        Swal.fire({
            title: 'Detalle del asistente',
            html: html,
            width: '46rem',
            confirmButtonText: 'Cerrar',
            confirmButtonColor: '#b91830',
            customClass: {
                popup: 'rt-ev-att-detail-popup shadow',
                htmlContainer: 'text-start px-3 py-2 rt-ev-detail-html',
            },
            showCloseButton: true,
            didOpen: function () {
                var mount = document.getElementById('rt-ev-detail-qr');
                if (!mount) {
                    return;
                }
                mount.innerHTML = '';
                var code = row.security_code ? String(row.security_code) : '';
                if (!code || typeof QRCode === 'undefined') {
                    mount.innerHTML =
                        '<span class="text-muted small">' +
                        (code ? 'No se pudo generar el QR' : '—') +
                        '</span>';
                    return;
                }
                try {
                    new QRCode(mount, {
                        text: code,
                        width: 176,
                        height: 176,
                        colorDark: '#1c1c1e',
                        colorLight: '#ffffff',
                        correctLevel: QRCode.CorrectLevel.M,
                    });
                } catch (err) {
                    mount.innerHTML =
                        '<span class="text-muted small">No se pudo generar el QR</span>';
                }
            },
        });
    }

    window.actionEvents = {
        'click .rt-ev-btn-detail': function (e, value, row) {
            e.preventDefault();
            e.stopPropagation();
            openAttendeeDetail(row);
        },
        'click .rt-ev-btn-checkin': function (e, value, row) {
            e.preventDefault();
            e.stopPropagation();
            var root = readRoot();
            if (!root) {
                return;
            }
            global.rtEvAttendeesDoCheckIn(root, row);
        },
        'click .rt-ev-btn-undo': function (e, value, row) {
            e.preventDefault();
            e.stopPropagation();
            var root = readRoot();
            if (!root) {
                return;
            }
            global.rtEvAttendeesDoUndo(root, row);
        },
        'click .rt-ev-btn-resend': function (e, value, row) {
            e.preventDefault();
            e.stopPropagation();
            var url = row.resend_tickets_url;
            if (!url) {
                return;
            }
            var root = readRoot();
            var csrf = root ? root.getAttribute('data-csrf') : '';
            fetch(url, {
                method: 'POST',
                headers: {
                    Accept: 'application/json',
                    'Content-Type': 'application/json',
                    'X-CSRF-TOKEN': csrf,
                    'X-Requested-With': 'XMLHttpRequest',
                },
                credentials: 'same-origin',
                body: '{}',
            })
                .then(function (r) {
                    return r.json().then(function (body) {
                        if (!r.ok) {
                            var msg = body.message || 'Error';
                            throw new Error(msg);
                        }
                        return body;
                    });
                })
                .then(function (body) {
                    if (typeof Swal !== 'undefined') {
                        Swal.fire({
                            icon: 'success',
                            title: body.message || 'Correo enviado',
                            toast: true,
                            position: 'top-end',
                            showConfirmButton: false,
                            timer: 2600,
                            timerProgressBar: true,
                        });
                    }
                })
                .catch(function (err) {
                    if (typeof Swal !== 'undefined') {
                        Swal.fire({
                            icon: 'error',
                            title: err.message || 'No se pudo reenviar',
                            confirmButtonColor: '#b91830',
                        });
                    }
                });
        },
    };

    function updateStats(stats) {
        var total = document.getElementById('rt-ev-stat-total');
        var inn = document.getElementById('rt-ev-stat-in');
        var pend = document.getElementById('rt-ev-stat-pend');
        var rate = document.getElementById('rt-ev-stat-rate');
        if (!stats || !total) {
            return;
        }
        var t = stats.total || 0;
        var c = stats.checked_in || 0;
        var p = stats.pending != null ? stats.pending : Math.max(0, t - c);
        total.textContent = t;
        inn.textContent = c;
        pend.textContent = p;
        rate.textContent = t > 0 ? Math.round((c / t) * 100) + '%' : '—';
    }

    function setLoadedAt() {
        var el = document.getElementById('rt-ev-att-loaded-at');
        if (!el || typeof Intl === 'undefined') {
            return;
        }
        try {
            el.textContent =
                'Actualizado ' +
                new Date().toLocaleString('es', { dateStyle: 'short', timeStyle: 'short' });
        } catch (e) {
            el.textContent = '';
        }
    }

    global.rtEvAttendeesDoCheckIn = function (root, row) {
        var csrf = root.getAttribute('data-csrf');
        var base = root.getAttribute('data-asistentes-base-url');
        var $table = global.jQuery ? global.jQuery('#rt-ev-attendees-table') : null;
        if (!csrf || !base || !$table || !row || !row.id) {
            return;
        }
        var url = base + '/' + row.id + '/check-in';
        postJson(url, csrf)
            .then(function (res) {
                if (res.attendee) {
                    $table.bootstrapTable('updateByUniqueId', {
                        id: row.id,
                        row: res.attendee,
                    });
                }
                if (typeof Swal !== 'undefined') {
                    Swal.fire({
                        icon: 'success',
                        title: res.message || 'Listo',
                        toast: true,
                        position: 'top-end',
                        showConfirmButton: false,
                        timer: 2600,
                        timerProgressBar: true,
                    });
                }
                refreshStatsFromTable($table);
            })
            .catch(function (err) {
                var msg =
                    err.body && err.body.message
                        ? err.body.message
                        : err.message || 'No se pudo completar el check-in.';
                if (typeof Swal !== 'undefined') {
                    Swal.fire({ icon: 'info', title: msg, confirmButtonColor: '#b91830' });
                } else {
                    alert(msg);
                }
            });
    };

    global.rtEvAttendeesDoUndo = function (root, row) {
        var csrf = root.getAttribute('data-csrf');
        var base = root.getAttribute('data-asistentes-base-url');
        var $table = global.jQuery ? global.jQuery('#rt-ev-attendees-table') : null;
        if (!csrf || !base || !$table || !row || !row.id) {
            return;
        }
        if (typeof Swal !== 'undefined') {
            Swal.fire({
                icon: 'question',
                title: '¿Anular check-in?',
                text: row.holder_name || '',
                showCancelButton: true,
                confirmButtonText: 'Sí, anular',
                cancelButtonText: 'Cancelar',
                confirmButtonColor: '#b91830',
            }).then(function (r) {
                if (!r.isConfirmed) {
                    return;
                }
                undoRequest(root, row, $table, csrf, base);
            });
        } else if (confirm('¿Anular check-in?')) {
            undoRequest(root, row, $table, csrf, base);
        }
    };

    function undoRequest(root, row, $table, csrf, base) {
        var url = base + '/' + row.id + '/undo-check-in';
        postJson(url, csrf)
            .then(function (res) {
                if (res.attendee) {
                    $table.bootstrapTable('updateByUniqueId', {
                        id: row.id,
                        row: res.attendee,
                    });
                }
                if (typeof Swal !== 'undefined') {
                    Swal.fire({
                        icon: 'success',
                        title: res.message || 'Anulado',
                        toast: true,
                        position: 'top-end',
                        showConfirmButton: false,
                        timer: 2400,
                        timerProgressBar: true,
                    });
                }
                refreshStatsFromTable($table);
            })
            .catch(function (err) {
                var msg =
                    err.body && err.body.message
                        ? err.body.message
                        : err.message || 'No se pudo anular.';
                if (typeof Swal !== 'undefined') {
                    Swal.fire({ icon: 'error', title: msg, confirmButtonColor: '#b91830' });
                } else {
                    alert(msg);
                }
            });
    }

    function refreshStatsFromTable($table) {
        var data = $table.bootstrapTable('getData');
        var total = data.length;
        var checked = data.filter(function (r) {
            return r.checked_in;
        }).length;
        updateStats({
            total: total,
            checked_in: checked,
            pending: total - checked,
        });
    }

    function highlightRow($table, id) {
        var data = $table.bootstrapTable('getData');
        var idx = -1;
        for (var i = 0; i < data.length; i++) {
            if (String(data[i].id) === String(id)) {
                idx = i;
                break;
            }
        }
        if (idx < 0) {
            return;
        }
        try {
            if (typeof $table.bootstrapTable === 'function') {
                $table.bootstrapTable('scrollTo', idx);
            }
        } catch (e) {
            try {
                $table.bootstrapTable('scrollTo', { unit: 'rows', value: idx });
            } catch (e2) {
                /* ignore */
            }
        }
        var $rows = $table.closest('.bootstrap-table').find('tbody tr');
        $rows.removeClass('rt-ev-att-row-flash');
        var $r = $rows.eq(idx);
        $r.addClass('rt-ev-att-row-flash');
        setTimeout(function () {
            $r.removeClass('rt-ev-att-row-flash');
        }, 2200);
    }

    var rtEvQrEngine = null;
    var rtEvQrActive = false;
    var rtEvQrLastTs = 0;

    function postScan(url, csrf, code) {
        return fetch(url, {
            method: 'POST',
            headers: {
                Accept: 'application/json',
                'Content-Type': 'application/json',
                'X-CSRF-TOKEN': csrf,
                'X-Requested-With': 'XMLHttpRequest',
            },
            credentials: 'same-origin',
            body: JSON.stringify({ code: code }),
        }).then(function (r) {
            return r.json().then(function (body) {
                return { ok: r.ok, status: r.status, body: body };
            });
        });
    }

    /**
     * Puerta: mismo flujo que POST /scan en rt-checkin (registrar o avisar duplicado).
     */
    function runDoorScan(root, $table, rawCode, fromCamera) {
        var scanUrl = root.getAttribute('data-scan-url');
        var csrf = root.getAttribute('data-csrf');
        var hint = document.getElementById('rt-ev-att-scan-hint');
        fromCamera = !!fromCamera;

        if (!scanUrl || !csrf) {
            return;
        }
        var code = rawCode == null ? '' : String(rawCode);
        if (!code.trim()) {
            if (hint) {
                hint.textContent = 'Escribe o pega el código.';
            }
            return;
        }

        postScan(scanUrl, csrf, code)
            .then(function (res) {
                var body = res.body;
                if (!res.ok) {
                    var msg = body.message || 'Error';
                    if (hint) {
                        hint.textContent = msg;
                    }
                    if (typeof Swal !== 'undefined') {
                        Swal.fire({
                            icon: res.status === 422 ? 'info' : 'error',
                            title: res.status === 404 ? 'Sin coincidencia' : 'No válido',
                            text: msg,
                            confirmButtonColor: '#b91830',
                        });
                    }
                    return;
                }

                var att = body.attendee;
                if (!att || !att.id) {
                    return;
                }

                $table.bootstrapTable('updateByUniqueId', { id: att.id, row: att });
                refreshStatsFromTable($table);
                highlightRow($table, att.id);

                var inp = document.getElementById('rt-ev-att-scan-input');
                if (inp) {
                    inp.value = '';
                    if (!fromCamera) {
                        inp.focus();
                    }
                }

                if (hint) {
                    if (body.code === 'ALREADY_CHECKED_IN') {
                        hint.textContent =
                            'Ya ingresó: ' +
                            (att.holder_name || '') +
                            ' · ' +
                            (att.checked_in_at_label || '');
                    } else {
                        hint.textContent =
                            'Registrado: ' + (att.holder_name || '') + ' · ' + (att.ticket_type || '');
                    }
                }

                if (typeof Swal !== 'undefined') {
                    if (fromCamera) {
                        Swal.fire({
                            icon: body.code === 'ALREADY_CHECKED_IN' ? 'warning' : 'success',
                            title:
                                body.code === 'ALREADY_CHECKED_IN'
                                    ? 'Ya registrado'
                                    : 'Acceso autorizado',
                            text: body.message || '',
                            toast: true,
                            position: 'top-end',
                            timer: body.code === 'ALREADY_CHECKED_IN' ? 3200 : 2400,
                            showConfirmButton: false,
                            timerProgressBar: true,
                        });
                    } else {
                        Swal.fire({
                            icon: body.code === 'ALREADY_CHECKED_IN' ? 'warning' : 'success',
                            title:
                                body.code === 'ALREADY_CHECKED_IN'
                                    ? 'Ya registrado'
                                    : body.message || 'Acceso autorizado',
                            html:
                                '<div class="text-left small">' +
                                '<strong>' +
                                textEscape(att.holder_name || '') +
                                '</strong><br>' +
                                textEscape(att.ticket_type || '') +
                                '</div>',
                            confirmButtonColor: '#b91830',
                        });
                    }
                }
            })
            .catch(function () {
                if (hint) {
                    hint.textContent = 'Error de red. Intenta de nuevo.';
                }
            });
    }

    function setupDoorCamera(root, $table) {
        var toggle = document.getElementById('rt-ev-att-cam-toggle');
        var readerEl = document.getElementById('rt-ev-qr-reader');
        var labelEl = document.getElementById('rt-ev-att-cam-toggle-label');
        var camHint = document.getElementById('rt-ev-att-cam-hint');
        if (!toggle || !readerEl) {
            return;
        }

        function stopCam() {
            if (!rtEvQrEngine || !rtEvQrActive) {
                readerEl.classList.add('d-none');
                if (labelEl) {
                    labelEl.textContent = 'Activar cámara';
                }
                toggle.setAttribute('aria-pressed', 'false');
                return;
            }
            rtEvQrEngine
                .stop()
                .then(function () {
                    rtEvQrEngine.clear();
                    rtEvQrEngine = null;
                    rtEvQrActive = false;
                    readerEl.classList.add('d-none');
                    if (labelEl) {
                        labelEl.textContent = 'Activar cámara';
                    }
                    toggle.setAttribute('aria-pressed', 'false');
                })
                .catch(function () {
                    rtEvQrEngine = null;
                    rtEvQrActive = false;
                    readerEl.classList.add('d-none');
                });
        }

        toggle.addEventListener('click', function () {
            if (rtEvQrActive) {
                stopCam();
                return;
            }
            if (typeof Html5Qrcode === 'undefined') {
                if (typeof Swal !== 'undefined') {
                    Swal.fire({
                        icon: 'info',
                        title: 'Cámara no disponible',
                        text: 'No se cargó la librería de lectura QR. Recarga la página.',
                        confirmButtonColor: '#b91830',
                    });
                }
                return;
            }

            readerEl.classList.remove('d-none');
            readerEl.innerHTML = '';
            rtEvQrEngine = new Html5Qrcode('rt-ev-qr-reader');

            var config = { fps: 8, qrbox: { width: 220, height: 220 } };
            var onScan = function (decodedText) {
                var now = Date.now();
                if (now - rtEvQrLastTs < 2000) {
                    return;
                }
                rtEvQrLastTs = now;
                runDoorScan(root, $table, decodedText, true);
            };

            rtEvQrEngine
                .start({ facingMode: 'environment' }, config, onScan, function () {})
                .then(function () {
                    rtEvQrActive = true;
                    if (labelEl) {
                        labelEl.textContent = 'Detener cámara';
                    }
                    toggle.setAttribute('aria-pressed', 'true');
                    if (camHint) {
                        camHint.textContent =
                            'Escaneando… El ingreso se registra al detectar el QR.';
                    }
                })
                .catch(function () {
                    if (typeof Swal !== 'undefined') {
                        Swal.fire({
                            icon: 'error',
                            title: 'No se pudo abrir la cámara',
                            text: 'Permite el acceso a la cámara o usa lector USB / pegado.',
                            confirmButtonColor: '#b91830',
                        });
                    }
                    readerEl.classList.add('d-none');
                    rtEvQrEngine = null;
                });
        });
    }

    function setupAttendeesOverviewModal() {
        var btn = document.getElementById('rt-ev-overview-btn');
        var source = document.getElementById('rt-ev-overview-html-source');
        if (!btn || !source || typeof Swal === 'undefined') {
            return;
        }
        if (btn.getAttribute('data-rt-overview-bound') === '1') {
            return;
        }
        btn.setAttribute('data-rt-overview-bound', '1');
        btn.addEventListener('click', function () {
            var html = source.innerHTML;
            Swal.fire({
                title: 'Resumen del evento',
                html: html,
                width: 'min(52rem, calc(100vw - 1.25rem))',
                confirmButtonText: 'Cerrar',
                confirmButtonColor: '#b91830',
                showCloseButton: true,
                customClass: {
                    popup: 'rt-ev-overview-swal shadow',
                    htmlContainer: 'text-start px-2 py-2 rt-ev-overview-swal-html',
                },
                didOpen: function () {
                    var container = Swal.getHtmlContainer();
                    if (!container || !global.jQuery) {
                        return;
                    }
                    var $c = global.jQuery(container);
                    $c.find('.rt-ev-sw-nav a[data-toggle="tab"]').on('click', function (e) {
                        e.preventDefault();
                        global.jQuery(this).tab('show');
                    });
                },
            });
        });
    }

    global.rtInitEventAttendees = function () {
        setupAttendeesOverviewModal();

        var root = readRoot();
        if (!root || !global.jQuery || !global.jQuery.fn.bootstrapTable) {
            return;
        }

        var $table = global.jQuery('#rt-ev-attendees-table');
        var dataUrl = root.getAttribute('data-data-url');
        var csrf = root.getAttribute('data-csrf');

        var columns = [
            {
                field: 'holder_name',
                title: 'Información del asistente',
                sortable: true,
                formatter: attendeeInfoFormatter,
                class: 'ps-3 align-top rt-ev-att-col-info',
            },
            { field: 'ticket_type', title: 'Entrada', sortable: true, class: 'align-top' },
            {
                field: 'order_status',
                title: 'Estado orden',
                sortable: true,
                formatter: orderStatusFormatter,
                class: 'align-top',
            },
            {
                field: 'checked_in',
                title: 'Check-in',
                sortable: true,
                formatter: statusFormatter,
                class: 'align-top',
            },
            {
                field: 'extras',
                title: 'Registro',
                sortable: true,
                formatter: registroFormatter,
                class: 'align-top',
            },
            { field: 'checked_in_at_label', title: 'Ingreso', sortable: true, class: 'align-top small' },
            { field: 'checked_in_by', title: 'Registró ingreso', sortable: true, class: 'align-top small' },
            {
                field: 'actions',
                title: 'Acciones',
                formatter: actionsFormatter,
                events: window.actionEvents,
                switchable: false,
                align: 'center',
                class: 'pe-3 text-nowrap align-top',
            },
        ];

        fetch(dataUrl, {
            headers: { Accept: 'application/json', 'X-Requested-With': 'XMLHttpRequest' },
            credentials: 'same-origin',
        })
            .then(function (r) {
                return r.json();
            })
            .then(function (payload) {
                updateStats(payload.stats || {});
                setLoadedAt();

                $table.bootstrapTable({
                    locale: 'es-ES',
                    classes: 'table table-hover table-bordered border-0',
                    theadClasses: 'thead-light',
                    uniqueId: 'id',
                    columns: columns,
                    data: payload.rows || [],
                    search: true,
                    searchHighlight: true,
                    showColumns: true,
                    showFullscreen: true,
                    pagination: true,
                    pageSize: 25,
                    pageList: [10, 25, 50, 100, 'all'],
                    paginationPreText: 'Anterior',
                    paginationNextText: 'Siguiente',
                    sortName: 'holder_name',
                    sortOrder: 'asc',
                    showExport: true,
                    exportDataType: 'all',
                    exportTypes: ['excel', 'csv'],
                    formatNoMatches: function () {
                        return 'No hay asistentes con orden completada para este evento.';
                    },
                });

                var scanBtn = document.getElementById('rt-ev-att-scan-btn');
                var scanInput = document.getElementById('rt-ev-att-scan-input');
                if (scanBtn && scanInput) {
                    scanBtn.addEventListener('click', function () {
                        runDoorScan(root, $table, scanInput.value, false);
                    });
                    scanInput.addEventListener('keydown', function (ev) {
                        if (ev.key === 'Enter') {
                            ev.preventDefault();
                            runDoorScan(root, $table, scanInput.value, false);
                        }
                    });
                }
                setupDoorCamera(root, $table);
            })
            .catch(function () {
                updateStats({ total: 0, checked_in: 0, pending: 0 });
                if (typeof Swal !== 'undefined') {
                    Swal.fire({
                        icon: 'error',
                        title: 'No se pudieron cargar los datos',
                        text: 'Comprueba tu conexión e intenta recargar.',
                        confirmButtonColor: '#b91830',
                    });
                }
            });
    };
})(typeof window !== 'undefined' ? window : this);
