<?php
// Widget de Accesibilidad
// Requiere que $base esté definido (en banner.php)
if (!isset($base)) { $base = ''; }
?>
<style>
/* Tarjeta flotante de instrucciones TTS */
.tts-card {
    position: fixed;
    right: 85px;
    top: 90px;
    max-width: 280px;
    padding: 16px 20px;
    border-radius: 12px;
    background: linear-gradient(135deg, #1b5e20, #2e7d32);
    color: #fff;
    font-size: 14px;
    line-height: 1.4;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
    z-index: 9997;
    animation: slideInRight 0.5s ease;
    display: none;
}

.tts-card.show {
    display: block;
}

/* Efecto decorativo */
.tts-card::before {
    content: "🔊";
    position: absolute;
    font-size: 50px;
    opacity: 0.12;
    top: -5px;
    right: 8px;
    pointer-events: none;
}

/* Texto */
.tts-card p {
    margin: 0;
    font-weight: 500;
    position: relative;
    z-index: 1;
}

/* Botón cerrar */
.tts-card-close {
    position: absolute;
    top: 6px;
    right: 8px;
    background: rgba(255, 255, 255, 0.2);
    border: none;
    color: #fff;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    cursor: pointer;
    font-size: 14px;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.2s;
    z-index: 2;
}

.tts-card-close:hover {
    background: rgba(255, 255, 255, 0.3);
}

/* Animación de entrada */
@keyframes slideInRight {
    from {
        opacity: 0;
        transform: translateX(30px);
    }

    to {
        opacity: 1;
        transform: translateX(0);
    }
}

/* Responsive */
@media (max-width: 768px) {
    .tts-card {
        right: 10px;
        top: 130px;
        max-width: calc(100vw - 80px);
        font-size: 13px;
        padding: 14px 18px;
    }
}
</style>
<!-- ══════════════════════════════════════════════════
     BOTÓN FLOTANTE TTS (ESCUCHAR TEXTO)
     ══════════════════════════════════════════════════ -->
<button type="button" class="tts-fab" id="ttsFab" aria-label="Escuchar texto" aria-pressed="false"
    title="Escuchar el contenido de la página o el texto seleccionado">
    <span class="tts-fab-icon">🔊</span>
</button>

<div class="tts-card show" id="ttsCard" role="region" aria-live="polite" aria-atomic="true">
    <button type="button" class="tts-card-close" id="ttsCardClose" aria-label="Cerrar instrucción">✕</button>
    <p>💡 Selecciona el texto que deseas escuchar y haz clic en el botón de altavoz.</p>
</div>

<!-- ══════════════════════════════════════════════════
     WIDGET DE ACCESIBILIDAD
     ══════════════════════════════════════════════════ -->
<button type="button" class="a11y-fab" id="a11yFab" aria-label="Abrir herramientas de accesibilidad"
    aria-controls="a11yPanel" aria-expanded="false" title="Accesibilidad">
    <svg viewBox="0 0 24 24" aria-hidden="true">
        <path d="M12 2a2 2 0 1 1 0 4 2 2 0 0 1 0-4zm9 6h-6v14h-2v-6h-2v6H9V8H3V6h18v2zm-9 2.5l-1.5 4.5h3L12 10.5z" />
    </svg>
</button>

<div class="a11y-panel" id="a11yPanel" role="dialog" aria-modal="false" aria-labelledby="a11yPanelTitle">
    <div class="a11y-panel-head">
        <h3 id="a11yPanelTitle">Accesibilidad</h3>
        <button type="button" class="a11y-panel-close" id="a11yPanelClose" aria-label="Cerrar panel">✕</button>
    </div>

    <div class="a11y-grid">
        <button type="button" class="a11y-btn" data-a11y="font-up" title="Aumentar tamaño de letra">
            <span class="a11y-ico">A+</span>
            <span>Aumentar texto</span>
        </button>
        <button type="button" class="a11y-btn" data-a11y="font-down" title="Disminuir tamaño de letra">
            <span class="a11y-ico">A-</span>
            <span>Disminuir texto</span>
        </button>
        <button type="button" class="a11y-btn" data-a11y="grayscale" aria-pressed="false" title="Blanco y negro">
            <span class="a11y-ico">◐</span>
            <span>Blanco y negro</span>
        </button>
        <button type="button" class="a11y-btn" data-a11y="high-contrast" aria-pressed="false" title="Alto contraste">
            <span class="a11y-ico">◑</span>
            <span>Alto contraste</span>
        </button>
        <button type="button" class="a11y-btn" data-a11y="negative" aria-pressed="false" title="Contraste negativo">
            <span class="a11y-ico">⬛</span>
            <span>Contraste negativo</span>
        </button>
        <button type="button" class="a11y-btn" data-a11y="light-bg" aria-pressed="false" title="Fondo claro">
            <span class="a11y-ico">☀</span>
            <span>Fondo claro</span>
        </button>
        <button type="button" class="a11y-btn" data-a11y="underline" aria-pressed="false" title="Subrayar enlaces">
            <span class="a11y-ico">U̲</span>
            <span>Subrayar enlaces</span>
        </button>
        <button type="button" class="a11y-btn" data-a11y="readable" aria-pressed="false" title="Texto legible">
            <span class="a11y-ico">Aa</span>
            <span>Texto legible</span>
        </button>
    </div>

    <button type="button" class="a11y-reset" id="a11yReset" title="Restablecer todas las opciones">
        ↺ Restablecer
    </button>
</div>

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

    var STORAGE_KEY = 'demo_a11y_v1';
    var FONT_LEVELS = ['a11y-font-n2', 'a11y-font-n1', '', 'a11y-font-1', 'a11y-font-2', 'a11y-font-3'];
    var FONT_BASE_INDEX = 2;
    var FONT_MIN = 0,
        FONT_MAX = FONT_LEVELS.length - 1;

    var html = document.documentElement;
    var fab = document.getElementById('a11yFab');
    var panel = document.getElementById('a11yPanel');
    var btnClose = document.getElementById('a11yPanelClose');
    var btnReset = document.getElementById('a11yReset');
    var allBtns = panel.querySelectorAll('.a11y-btn');

    // Estado inicial
    var state = {
        fontIndex: FONT_BASE_INDEX,
        grayscale: false,
        highContrast: false,
        negative: false,
        lightBg: false,
        underline: false,
        readable: false
    };

    // Cargar persistencia
    try {
        var saved = localStorage.getItem(STORAGE_KEY);
        if (saved) {
            var s = JSON.parse(saved);
            for (var k in s)
                if (state.hasOwnProperty(k)) state[k] = s[k];
        }
    } catch (e) {
        /* ignore */
    }

    function save() {
        try {
            localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
        } catch (e) {}
    }

    function applyState() {
        // Limpiar clases de fuente
        FONT_LEVELS.forEach(function(c) {
            if (c) html.classList.remove(c);
        });
        var fc = FONT_LEVELS[state.fontIndex];
        if (fc) html.classList.add(fc);

        html.classList.toggle('a11y-grayscale', state.grayscale);
        html.classList.toggle('a11y-high-contrast', state.highContrast);
        html.classList.toggle('a11y-negative', state.negative);
        html.classList.toggle('a11y-light-bg', state.lightBg);
        html.classList.toggle('a11y-underline', state.underline);
        html.classList.toggle('a11y-readable', state.readable);

        updateButtonStates();
    }

    function updateButtonStates() {
        allBtns.forEach(function(b) {
            var key = b.getAttribute('data-a11y');
            var active = false;
            if (key === 'grayscale') active = state.grayscale;
            else if (key === 'high-contrast') active = state.highContrast;
            else if (key === 'negative') active = state.negative;
            else if (key === 'light-bg') active = state.lightBg;
            else if (key === 'underline') active = state.underline;
            else if (key === 'readable') active = state.readable;
            if (key !== 'font-up' && key !== 'font-down') {
                b.classList.toggle('is-active', !!active);
                b.setAttribute('aria-pressed', active ? 'true' : 'false');
            }
        });
        updateTTSButton();
    }

    // ────────── Toggle del panel ──────────
    function openPanel() {
        panel.classList.add('is-open');
        fab.setAttribute('aria-expanded', 'true');
    }

    function closePanel() {
        panel.classList.remove('is-open');
        fab.setAttribute('aria-expanded', 'false');
    }
    fab.addEventListener('click', function() {
        panel.classList.contains('is-open') ? closePanel() : openPanel();
    });
    btnClose.addEventListener('click', closePanel);
    document.addEventListener('keydown', function(e) {
        if (e.key === 'Escape' && panel.classList.contains('is-open')) closePanel();
    });

    // ────────── Botón flotante TTS ──────────
    var ttsFab = document.getElementById('ttsFab');
    var ttsCard = document.getElementById('ttsCard');
    var ttsCardClose = document.getElementById('ttsCardClose');

    ttsFab.addEventListener('click', function() {
        ttsActive ? stopTTS() : startTTS();
    });

    // Cerrar tarjeta de instrucciones
    if (ttsCardClose) {
        ttsCardClose.addEventListener('click', function() {
            ttsCard.classList.remove('show');
            try {
                localStorage.setItem('tts_card_dismissed', 'true');
            } catch (e) {}
        });
    }

    // Ocultar tarjeta después de 10 segundos
    setTimeout(function() {
        if (ttsCard) ttsCard.classList.remove('show');
    }, 10000);

    // Verificar si ya fue cerrada antes
    try {
        if (localStorage.getItem('tts_card_dismissed') === 'true' && ttsCard) {
            ttsCard.classList.remove('show');
        }
    } catch (e) {}

    function updateTTSButton() {
        ttsFab.classList.toggle('is-active', ttsActive);
        ttsFab.setAttribute('aria-pressed', ttsActive ? 'true' : 'false');
    }

    // ────────── Text-to-Speech ──────────
    var ttsActive = false;
    var synth = window.speechSynthesis || null;
    var utterance = null;
    var ttsChunks = [];
    var ttsChunkIdx = 0;
    var ttsVoice = null;
    var ttsWatchdog = null;

    function pickSpanishVoice() {
        if (!synth) return null;
        var voices = synth.getVoices();
        var v = voices.find(function(vv) {
                return /^es(-|_)?MX/i.test(vv.lang);
            }) ||
            voices.find(function(vv) {
                return /^es/i.test(vv.lang);
            }) ||
            voices[0];
        return v || null;
    }

    function getReadableText() {
        var sel = window.getSelection ? window.getSelection().toString().trim() : '';
        if (sel) return sel;
        // Preferir <main> -> <article> -> contenedor común -> body
        var main = document.querySelector('main') ||
            document.querySelector('article') ||
            document.querySelector('.main-content') ||
            document.querySelector('.doc-shell') ||
            document.querySelector('.doc-paper') ||
            document.body;
        // Excluir nav, footer, panel a11y
        var clone = main.cloneNode(true);
        clone.querySelectorAll(
                'script, style, nav, footer, .site-banner, .site-nav, .site-footer, .a11y-panel, .a11y-fab, .tts-fab, .tts-card'
            )
            .forEach(function(n) {
                n.remove();
            });
        var txt = (clone.innerText || clone.textContent || '').replace(/\s+/g, ' ').trim();
        return txt;
    }

    // Divide el texto en fragmentos cortos (~140 chars) respetando puntos y comas.
    // Chrome corta utterances de más de ~200 caracteres o ~15 segundos.
    function splitIntoChunks(text, maxLen) {
        maxLen = maxLen || 140;
        var chunks = [];
        // Primero por oración
        var sentences = text.match(/[^.!?¡¿]+[.!?]+|[^.!?¡¿]+$/g) || [text];
        sentences.forEach(function(s) {
            s = s.trim();
            if (!s) return;
            if (s.length <= maxLen) {
                chunks.push(s);
                return;
            }
            // Si la oración es muy larga, partir por comas
            var parts = s.split(/,\s+/);
            var buf = '';
            parts.forEach(function(p) {
                p = p.trim();
                if (!p) return;
                if (p.length > maxLen) {
                    // partir por palabras
                    if (buf) {
                        chunks.push(buf.trim());
                        buf = '';
                    }
                    var words = p.split(/\s+/);
                    var line = '';
                    words.forEach(function(w) {
                        if ((line + ' ' + w).trim().length > maxLen) {
                            if (line) chunks.push(line.trim());
                            line = w;
                        } else {
                            line = (line ? line + ' ' : '') + w;
                        }
                    });
                    if (line) chunks.push(line.trim());
                } else if ((buf + ', ' + p).length > maxLen) {
                    if (buf) chunks.push(buf.trim());
                    buf = p;
                } else {
                    buf = (buf ? buf + ', ' : '') + p;
                }
            });
            if (buf.trim()) chunks.push(buf.trim());
        });
        return chunks.filter(function(c) {
            return c && c.length > 0;
        });
    }

    function clearWatchdog() {
        if (ttsWatchdog) {
            clearTimeout(ttsWatchdog);
            ttsWatchdog = null;
        }
    }

    function speakNextChunk() {
        clearWatchdog();
        if (!ttsActive || ttsChunkIdx >= ttsChunks.length) {
            ttsActive = false;
            updateTTSButton();
            return;
        }
        var text = ttsChunks[ttsChunkIdx++];
        utterance = new SpeechSynthesisUtterance(text);
        utterance.lang = 'es-MX';
        utterance.rate = 1;
        utterance.pitch = 1;
        if (ttsVoice) utterance.voice = ttsVoice;

        var advanced = false;

        function advance() {
            if (advanced) return;
            advanced = true;
            clearWatchdog();
            // Pequeño retardo para evitar race condition de Chrome al encadenar
            setTimeout(speakNextChunk, 30);
        }

        utterance.onend = advance;
        utterance.onerror = function(e) {
            // 'canceled'/'interrupted' = el usuario detuvo: no continuar
            if (e && (e.error === 'canceled' || e.error === 'interrupted')) {
                advanced = true;
                clearWatchdog();
                return;
            }
            advance();
        };

        try {
            synth.speak(utterance);
        } catch (err) {
            advance();
            return;
        }

        // Watchdog: si el motor se queda colgado (Chrome a veces simplemente no dispara onend),
        // estimamos duración por longitud (~70 ms por carácter a velocidad 1) y forzamos avance.
        var estimatedMs = Math.max(2500, text.length * 75) + 4000;
        ttsWatchdog = setTimeout(function() {
            // Si seguimos en el mismo chunk y el motor no está hablando, avanzar
            if (!advanced) {
                try {
                    synth.cancel();
                } catch (e) {}
                advance();
            }
        }, estimatedMs);
    }

    function startTTS() {
        if (!synth) {
            alert('Su navegador no admite la lectura de texto.');
            return;
        }
        // Cancelar cualquier reproducción previa y esperar antes de iniciar
        try {
            synth.cancel();
        } catch (e) {}
        var text = getReadableText();
        if (!text) return;
        ttsChunks = splitIntoChunks(text, 140);
        if (!ttsChunks.length) return;
        ttsChunkIdx = 0;
        ttsVoice = pickSpanishVoice();
        ttsActive = true;
        updateTTSButton();
        // Pequeño delay tras cancel() — Chrome necesita un tick para liberar la cola
        setTimeout(speakNextChunk, 120);
    }

    function stopTTS() {
        ttsActive = false;
        clearWatchdog();
        ttsChunks = [];
        ttsChunkIdx = 0;
        if (synth) {
            try {
                synth.cancel();
            } catch (e) {}
        }
        updateTTSButton();
    }

    // Pre-cargar voces (algunos navegadores cargan asíncrono)
    if (synth && typeof synth.onvoiceschanged !== 'undefined') {
        synth.onvoiceschanged = function() {
            ttsVoice = pickSpanishVoice();
        };
    }
    // Forzar carga inicial de voces
    if (synth) {
        try {
            synth.getVoices();
        } catch (e) {}
    }
    // Detener TTS al salir
    window.addEventListener('beforeunload', function() {
        if (synth) synth.cancel();
    });

    // ────────── Acciones de los botones ──────────
    allBtns.forEach(function(b) {
        b.addEventListener('click', function() {
            var key = b.getAttribute('data-a11y');
            switch (key) {
                case 'font-up':
                    if (state.fontIndex < FONT_MAX) state.fontIndex++;
                    break;
                case 'font-down':
                    if (state.fontIndex > FONT_MIN) state.fontIndex--;
                    break;
                case 'grayscale':
                    state.grayscale = !state.grayscale;
                    if (state.grayscale) {
                        state.highContrast = false;
                        state.negative = false;
                    }
                    break;
                case 'high-contrast':
                    state.highContrast = !state.highContrast;
                    if (state.highContrast) {
                        state.grayscale = false;
                        state.negative = false;
                        state.lightBg = false;
                    }
                    break;
                case 'negative':
                    state.negative = !state.negative;
                    if (state.negative) {
                        state.grayscale = false;
                        state.highContrast = false;
                        state.lightBg = false;
                    }
                    break;
                case 'light-bg':
                    state.lightBg = !state.lightBg;
                    if (state.lightBg) {
                        state.highContrast = false;
                        state.negative = false;
                    }
                    break;
                case 'underline':
                    state.underline = !state.underline;
                    break;
                case 'readable':
                    state.readable = !state.readable;
                    break;
            }
            applyState();
            save();
        });
    });

    // ────────── Restablecer ──────────
    btnReset.addEventListener('click', function() {
        stopTTS();
        state = {
            fontIndex: FONT_BASE_INDEX,
            grayscale: false,
            highContrast: false,
            negative: false,
            lightBg: false,
            underline: false,
            readable: false
        };
        applyState();
        save();
    });

    // Aplicar estado guardado al cargar
    applyState();
})();
</script>