// Componente Modular: Vista del Espectador / Jugador (Transmisión en Vivo y Juego Personal)
const { useState, useCallback, useEffect } = React;

function SpectatorView({ initialCards, onSwitchRole, currentUser }) {
  const room = window.useBingoRoom ? window.useBingoRoom() : {};

  // Determinar si el usuario actual tiene privilegios de Organizador
  const isOrganizer = (currentUser && (currentUser.originalRole === 'admin' || currentUser.adminPin === '1234')) || (() => {
    try {
      const u = JSON.parse(localStorage.getItem('bingo_session_user'));
      return u?.originalRole === 'admin' || u?.adminPin === '1234';
    } catch(e) {
      return false;
    }
  })();

  const calledBalls = room.calledBalls || [];
  const currentBall = room.currentBall || null;
  const showMatrix = room.showMatrix || false;
  const setShowMatrix = room.setShowMatrix || (() => {});
  const voiceEnabled = room.voiceEnabled !== undefined ? room.voiceEnabled : true;
  const setVoiceEnabled = room.setVoiceEnabled || (() => {});

  const prize1Winner = room.prize1Winner || null;
  const prizeBingoWinner = room.prizeBingoWinner || null;
  const prizeCardRaffleWinner = room.prizeCardRaffleWinner || null;
  const isRafflingCard = room.isRafflingCard || false;
  const raffleDisplayCode = room.raffleDisplayCode || 'CR-?????';
  const latestAnnouncement = room.latestAnnouncement || null;
  const setLatestAnnouncement = room.setLatestAnnouncement || (() => {});

  const radarRanking = room.radarRanking || [];
  const viewersCount = room.viewersCount || 52;
  const videoUrl = room.videoUrl || '';

  // Modo de video activo por defecto si hay video configurado
  const [videoModeActive, setVideoModeActive] = useState(false);

  // Estados para Modal de Configuración de Video / Transmisión
  const [showVideoConfigModal, setShowVideoConfigModal] = useState(false);
  const [inputVideoUrl, setInputVideoUrl] = useState(videoUrl || '');
  const [adminPinInput, setAdminPinInput] = useState('');
  const [videoSaveMsg, setVideoSaveMsg] = useState('');
  const [videoPinError, setVideoPinError] = useState('');
  const [isSavingVideo, setIsSavingVideo] = useState(false);

  // Información del video
  const videoInfo = React.useMemo(() => {
    if (!videoUrl) return null;
    const trimmed = videoUrl.trim();
    const ytMatch = trimmed.match(/(?:youtube\.com\/(?:watch\?v=|live\/|embed\/)|youtu\.be\/)([a-zA-Z0-9_-]{11})/);
    if (ytMatch) {
      return {
        type: 'youtube',
        embedUrl: `https://www.youtube.com/embed/${ytMatch[1]}?autoplay=1&mute=0&rel=0`,
        directUrl: trimmed
      };
    }
    const twitchMatch = trimmed.match(/twitch\.tv\/([a-zA-Z0-9_]+)/);
    if (twitchMatch) {
      return {
        type: 'twitch',
        embedUrl: `https://player.twitch.tv/?channel=${twitchMatch[1]}&parent=${window.location.hostname || 'localhost'}`,
        directUrl: trimmed
      };
    }
    if (trimmed.match(/\.(mp4|webm|ogg)($|\?)/i)) {
      return {
        type: 'html5',
        embedUrl: trimmed,
        directUrl: trimmed
      };
    }
    return {
      type: 'link',
      embedUrl: null,
      directUrl: trimmed
    };
  }, [videoUrl]);

  // Cartones personales del espectador (vacío por defecto si no ha comprado/consultado)
  const [userCards, setUserCards] = useState(() => (initialCards && initialCards.length > 0) ? initialCards : []);

  useEffect(() => {
    if (initialCards && initialCards.length > 0) {
      setUserCards(initialCards);
    }
  }, [initialCards]);

  const [showPdfModal, setShowPdfModal] = useState(false);
  const [inRoomQuery, setInRoomQuery] = useState('');
  const [inRoomLoading, setInRoomLoading] = useState(false);
  const [inRoomMsg, setInRoomMsg] = useState(null);

  const normalizePhone = (p) => {
    if (!p) return '';
    let clean = String(p).replace(/[^0-9]/g, '');
    if (clean.startsWith('549')) clean = clean.slice(3);
    else if (clean.startsWith('54')) clean = clean.slice(2);
    if (clean.startsWith('0')) clean = clean.slice(1);
    if (clean.startsWith('15')) clean = clean.slice(2);
    return clean;
  };

  const matchPhones = (p1, p2) => {
    const c1 = normalizePhone(p1);
    const c2 = normalizePhone(p2);
    if (!c1 || !c2) return false;
    if (c1 === c2) return true;
    const minLen = Math.min(c1.length, c2.length);
    if (minLen >= 6) {
      if (c1.endsWith(c2) || c2.endsWith(c1) || c1.includes(c2) || c2.includes(c1)) {
        return true;
      }
    }
    return false;
  };

  const performLookup = async (queryText) => {
    const targetQuery = (queryText !== undefined && queryText !== null ? queryText : inRoomQuery).trim();
    if (!targetQuery) return;
    setInRoomLoading(true);
    setInRoomMsg(null);

    try {
      const rawQuery = targetQuery.toLowerCase();
      const codeQuery = targetQuery.toUpperCase();
      let matchingReceipts = [];

      if (window.ReceiptService && window.ReceiptService.getReceipts) {
        const receipts = await window.ReceiptService.getReceipts();
        matchingReceipts = receipts.filter(r => {
          if (matchPhones(r.player_phone, targetQuery)) return true;
          if (matchPhones(r.phone, targetQuery)) return true;
          if (r.player_name && r.player_name.toLowerCase().includes(rawQuery)) return true;
          return false;
        });
      }

      if (matchingReceipts.length === 0 && window.supabaseClient) {
        const cleanDigits = codeQuery.replace(/[^0-9]/g, '');
        let cardMatches = [];
        const { data: bcMatches } = await window.supabaseClient
          .from('bingo_cards')
          .select('receipt_id, player_name, player_phone, card_code')
          .or(`card_code.ilike.%${codeQuery}%,card_code.ilike.%${cleanDigits}%`)
          .limit(10);
        if (bcMatches && bcMatches.length > 0) cardMatches = cardMatches.concat(bcMatches);

        const rIds = [...new Set(cardMatches.map(b => b.receipt_id).filter(Boolean))];
        if (rIds.length > 0) {
          const { data: foundRecs } = await window.supabaseClient
            .from('receipts')
            .select('*')
            .in('id', rIds);
          if (foundRecs && foundRecs.length > 0) matchingReceipts = foundRecs;
        }
      }

      let combinedCards = [];
      let playerName = 'Jugador';
      let playerPhone = targetQuery;

      if (matchingReceipts.length > 0) {
        playerName = matchingReceipts.find(r => r.player_name)?.player_name || 'Jugador';
        playerPhone = matchingReceipts.find(r => r.player_phone || r.phone)?.player_phone || targetQuery;

        for (const r of matchingReceipts) {
          let cards = (r.cards && r.cards.length > 0) ? r.cards : [];
          if (cards.length === 0 && window.ReceiptService?.getCardsByReceiptId) {
            cards = await window.ReceiptService.getCardsByReceiptId(r.id);
          }
          if (cards && cards.length > 0) combinedCards = combinedCards.concat(cards);
        }
      }

      if (combinedCards.length === 0 && window.supabaseClient) {
        const norm = normalizePhone(targetQuery);
        const { data: directBC } = await window.supabaseClient
          .from('bingo_cards')
          .select('*')
          .or(`player_phone.ilike.%${norm}%,player_name.ilike.%${rawQuery}%`);
        if (directBC && directBC.length > 0) {
          combinedCards = directBC.map((c, idx) => ({
            id: c.card_code || c.id,
            card_code: c.card_code || c.id,
            title: c.title || `Cartón Oficial #${idx + 1}`,
            playerName: c.player_name || playerName,
            playerPhone: c.player_phone || playerPhone,
            grid: c.grid,
            es_promo: c.es_promo,
            is_active: c.is_active
          }));
        }
      }

      if (combinedCards.length > 0) {
        const uniqueCards = [];
        const seenIds = new Set();
        for (const c of combinedCards) {
          const cid = c.card_code || c.id;
          if (!seenIds.has(cid)) {
            seenIds.add(cid);
            uniqueCards.push(c);
          }
        }

        setUserCards(uniqueCards);
        try {
          const userObj = {
            role: 'player',
            name: playerName,
            phone: playerPhone,
            cards: uniqueCards
          };
          localStorage.setItem('bingo_session_user', JSON.stringify(userObj));
        } catch(e) {}
        setInRoomMsg({ type: 'success', text: `¡Éxito! Se cargaron ${uniqueCards.length} cartones de ${playerName}.` });
      } else {
        setInRoomMsg({ type: 'error', text: 'No se encontraron cartones asociados a ese número. Verifica tu teléfono o código.' });
      }
    } catch(err) {
      console.error(err);
      setInRoomMsg({ type: 'error', text: 'Error al consultar. Intenta nuevamente.' });
    } finally {
      setInRoomLoading(false);
    }
  };

  const handleInRoomLookup = (e) => {
    if (e && e.preventDefault) e.preventDefault();
    performLookup(inRoomQuery);
  };

  // Auto-cargar cartones si el enlace de WhatsApp viene con ?phone= o ?card=
  useEffect(() => {
    try {
      const urlParams = new URLSearchParams(window.location.search);
      const urlPhone = urlParams.get('phone') || urlParams.get('tel') || urlParams.get('card');
      if (urlPhone) {
        setInRoomQuery(urlPhone);
        if (!initialCards || initialCards.length === 0) {
          performLookup(urlPhone);
        }
      }
    } catch(e) {
      console.error("Error al auto-cargar por URL:", e);
    }
  }, []);

  const handleToggleMatrix = useCallback(() => {
    setShowMatrix(prev => !prev);
  }, [setShowMatrix]);

  const handleToggleVoice = useCallback(() => {
    setVoiceEnabled(prev => !prev);
  }, [setVoiceEnabled]);

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: '20px' }}>
      {/* ========================================================
          BARRA DE ACCIONES PARA ORGANIZADOR EN VISTA DE ESPECTADOR
         ======================================================== */}
      {isOrganizer && (
        <div style={{
          background: 'linear-gradient(90deg, #1e1b4b, #312e81)',
          border: '1.5px solid var(--accent-gold)',
          borderRadius: 'var(--radius-lg)',
          padding: '12px 18px',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'space-between',
          flexWrap: 'wrap',
          gap: '12px',
          boxShadow: '0 4px 20px rgba(0, 0, 0, 0.45)',
          animation: 'popIn 0.3s ease'
        }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
            <span style={{
              background: 'var(--accent-gold)',
              color: '#111827',
              fontWeight: '900',
              padding: '4px 10px',
              borderRadius: 'var(--radius-sm)',
              fontSize: '0.82rem',
              letterSpacing: '0.5px',
              display: 'inline-flex',
              alignItems: 'center',
              gap: '6px'
            }}>
              <i className="fa-solid fa-user-shield"></i> MODO ORGANIZADOR
            </span>
            <span style={{ fontSize: '0.88rem', color: '#e0e7ff' }}>
              Estás viendo la pantalla tal como la ven los <strong>Espectadores</strong>.
            </span>
          </div>

          <div style={{ display: 'flex', alignItems: 'center', gap: '8px', flexWrap: 'wrap' }}>
            {onSwitchRole && (
              <button
                type="button"
                onClick={() => onSwitchRole('admin')}
                className="btn btn-accent btn-sm"
                style={{ fontWeight: '800', background: 'var(--accent-gold)', color: '#111827', padding: '7px 14px' }}
                title="Volver a la Mesa de Control Oficial del Bolillero"
              >
                <i className="fa-solid fa-gamepad"></i>
                <span>Volver a Mesa de Control</span>
              </button>
            )}

            <button
              type="button"
              onClick={() => {
                setInputVideoUrl(videoUrl);
                setShowVideoConfigModal(true);
                setVideoSaveMsg('');
                setVideoPinError('');
              }}
              className="btn btn-secondary btn-sm"
              style={{ fontWeight: '700', padding: '7px 14px', borderColor: 'rgba(56, 189, 248, 0.5)', color: '#38bdf8' }}
              title="Cargar o cambiar el enlace de transmisión en vivo de YouTube o Twitch"
            >
              <i className="fa-solid fa-video"></i>
              <span>{videoUrl ? 'Cambiar Video' : 'Cargar Link de Video'}</span>
            </button>

            <button
              type="button"
              onClick={() => room.toggleSalesStatus && room.toggleSalesStatus()}
              className={`btn btn-sm ${room.isSalesOpen ? 'btn-danger' : 'btn-success'}`}
              style={{ fontWeight: '800', padding: '7px 14px' }}
              title={room.isSalesOpen ? 'Cerrar la venta de cartones' : 'Abrir / Habilitar la venta de cartones'}
            >
              <i className={`fa-solid ${room.isSalesOpen ? 'fa-lock' : 'fa-lock-open'}`}></i>
              <span>{room.isSalesOpen ? 'Cerrar Ventas' : 'Abrir Ventas'}</span>
            </button>
          </div>
        </div>
      )}

      {/* ========================================================
          1. PODIO OFICIAL DE PREMIOS EN TRANSMISIÓN ($240.000 EN 3 RONDAS + GRAN SORTEO FINAL)
         ======================================================== */}
      <window.Premios 
        prize1Winner={prize1Winner}
        prizeBingoWinner={prizeBingoWinner}
        prizeCardRaffleWinner={prizeCardRaffleWinner}
        isRafflingCard={isRafflingCard}
        raffleDisplayCode={raffleDisplayCode}
        currentRound={room.currentRound}
        roundBingoPrize={room.roundBingoPrize}
        roundLineaPrize={room.roundLineaPrize}
        roundCartonPrize={room.roundCartonPrize}
        onSelectRound={isOrganizer ? room.setActiveRound : null}
      />

      {/* BANNER OFICIAL DE PREMIO CANTADO / COMPARTIDO EN VIVO */}
      {latestAnnouncement && (
        <div style={{
          background: 'linear-gradient(135deg, rgba(245, 158, 11, 0.15), rgba(16, 185, 129, 0.15))',
          border: '1px solid rgba(245, 158, 11, 0.5)',
          borderRadius: 'var(--radius-lg)',
          padding: '14px 20px',
          display: 'flex',
          justifyContent: 'space-between',
          alignItems: 'center',
          animation: 'popIn 0.3s ease',
          gap: '16px',
          boxShadow: '0 8px 24px rgba(245, 158, 11, 0.12)'
        }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: '14px' }}>
            <div style={{
              width: '44px',
              height: '44px',
              borderRadius: '50%',
              backgroundColor: 'rgba(245, 158, 11, 0.25)',
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
              fontSize: '1.25rem',
              color: 'var(--accent-gold)'
            }}>
              <i className="fa-solid fa-trophy"></i>
            </div>
            <div>
              <div style={{ fontSize: '0.98rem', fontWeight: '900', color: 'var(--accent-gold)' }}>
                {latestAnnouncement.title}
              </div>
              <div style={{ fontSize: '0.86rem', color: 'var(--text-main)', marginTop: '2px', fontWeight: '600' }}>
                {latestAnnouncement.message}
              </div>
            </div>
          </div>
          <div style={{ textAlign: 'right' }}>
            <div style={{ fontSize: '1.15rem', fontWeight: '900', color: 'var(--accent-green)' }}>
              {latestAnnouncement.amount}
            </div>
            <div style={{ fontSize: '0.72rem', color: 'var(--text-muted)' }}>
              🏆 ¡Premio Oficial!
            </div>
          </div>
        </div>
      )}

      {/* BANNER OFICIAL DE TRANSMISIÓN DE VIDEO CON BOLILLERO FÍSICO (Siempre visible) */}
      <div style={{
        background: 'linear-gradient(135deg, rgba(239, 68, 68, 0.16), rgba(245, 158, 11, 0.16))',
        border: '1.5px solid rgba(245, 158, 11, 0.45)',
        borderRadius: 'var(--radius-lg)',
        padding: '12px 18px',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'space-between',
        flexWrap: 'wrap',
        gap: '12px',
        animation: 'popIn 0.3s ease',
        boxShadow: '0 8px 24px rgba(239, 68, 68, 0.1)'
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
          <div style={{
            width: '42px',
            height: '42px',
            borderRadius: '50%',
            backgroundColor: 'rgba(239, 68, 68, 0.25)',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            fontSize: '1.25rem',
            color: '#f43f5e'
          }}>
            <i className="fa-solid fa-video"></i>
          </div>
          <div>
            <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
              <span className={`status-dot ${videoUrl ? 'online' : 'offline'}`} style={{ width: '8px', height: '8px', backgroundColor: videoUrl ? '#10b981' : '#f43f5e', boxShadow: videoUrl ? '0 0 10px #10b981' : '0 0 10px #f43f5e' }}></span>
              <strong style={{ fontSize: '0.98rem', color: '#fecdd3' }}>
                {videoUrl ? 'Transmisión en Video del Bolillero en Vivo' : 'Transmisión en Video del Bolillero'}
              </strong>
            </div>
            <div style={{ fontSize: '0.82rem', color: 'var(--text-muted)', marginTop: '2px' }}>
              {videoUrl ? 'Mira la extracción física de bolillas reales para máxima transparencia.' : 'El organizador puede configurar la transmisión en directo para todos los espectadores.'}
            </div>
          </div>
        </div>

        <div style={{ display: 'flex', alignItems: 'center', gap: '8px', flexWrap: 'wrap' }}>
          {videoUrl && videoInfo && videoInfo.embedUrl && (
            <button
              type="button"
              className={`btn btn-sm ${videoModeActive ? 'btn-primary' : 'btn-secondary'}`}
              onClick={() => setVideoModeActive(prev => !prev)}
              style={{ fontSize: '0.85rem', fontWeight: '800', display: 'flex', alignItems: 'center', gap: '6px' }}
            >
              <i className={`fa-solid ${videoModeActive ? 'fa-table-cells-large' : 'fa-play'}`}></i>
              {videoModeActive ? 'Ver Bolillero 3D' : 'Reproducir Video Aquí'}
            </button>
          )}

          {videoUrl && (
            <a
              href={videoUrl}
              target="_blank"
              rel="noopener noreferrer"
              className="btn btn-accent btn-sm"
              style={{
                fontSize: '0.85rem',
                fontWeight: '800',
                padding: '6px 14px',
                display: 'flex',
                alignItems: 'center',
                gap: '6px',
                background: 'var(--accent-gold)',
                color: '#111827',
                textDecoration: 'none'
              }}
              title="Abrir la transmisión en YouTube o app de video en pantalla completa"
            >
              <i className="fa-solid fa-arrow-up-right-from-square"></i>
              <span>Abrir Video (Pantalla Completa)</span>
            </a>
          )}

          {/* BOTÓN ULTRA DESTACADO JUSTO AL LADO DE ESAS OPCIONES */}
          <button
            type="button"
            onClick={() => {
              setInputVideoUrl(videoUrl);
              setShowVideoConfigModal(true);
              setVideoSaveMsg('');
              setVideoPinError('');
            }}
            className="btn btn-sm"
            style={{
              fontSize: '0.88rem',
              fontWeight: '900',
              padding: '7px 16px',
              display: 'inline-flex',
              alignItems: 'center',
              gap: '8px',
              background: 'linear-gradient(135deg, #0284c7, #0ea5e9)',
              color: '#ffffff',
              border: '2px solid #38bdf8',
              borderRadius: 'var(--radius-md)',
              boxShadow: '0 0 16px rgba(14, 165, 233, 0.5)',
              cursor: 'pointer'
            }}
            title="Cargar o cambiar el enlace de YouTube o video de la transmisión"
          >
            <i className="fa-solid fa-video" style={{ fontSize: '1rem', color: '#fff' }}></i>
            <span>{videoUrl ? 'Cargar / Cambiar Link de Video' : 'Cargar Link de Video'}</span>
          </button>
        </div>
      </div>

      {/* ========================================================
          2. STAGE PRINCIPAL: Transmisión y Gran Bolilla
         ======================================================== */}
      <div className="spectator-main-layout">
        <div className="spectator-stage-hero">
          {/* Si el espectador activó el video y es incrustable, mostrar el reproductor */}
          {videoModeActive && videoInfo && videoInfo.embedUrl ? (
            <div style={{ position: 'relative', width: '100%', borderRadius: 'var(--radius-lg)', overflow: 'hidden', background: '#000', border: '1px solid rgba(255, 255, 255, 0.1)', boxShadow: '0 8px 30px rgba(0,0,0,0.5)' }}>
              <div style={{ position: 'relative', paddingBottom: '56.25%', height: 0 }}>
                {videoInfo.type === 'youtube' || videoInfo.type === 'twitch' ? (
                  <iframe
                    src={videoInfo.embedUrl}
                    style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', border: 0 }}
                    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
                    allowFullScreen
                    title="Transmisión del Bolillero en Vivo"
                  ></iframe>
                ) : (
                  <video
                    src={videoInfo.embedUrl}
                    controls
                    autoPlay
                    style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }}
                  />
                )}
              </div>

              {/* HUD / Indicador en la esquina con la última bolilla cantada */}
              <div style={{
                position: 'absolute',
                bottom: '12px',
                left: '12px',
                backgroundColor: 'rgba(15, 23, 42, 0.9)',
                backdropFilter: 'blur(8px)',
                border: '1px solid rgba(245, 158, 11, 0.5)',
                borderRadius: 'var(--radius-md)',
                padding: '6px 14px',
                display: 'flex',
                alignItems: 'center',
                gap: '10px',
                color: '#fff',
                zIndex: 10
              }}>
                <div style={{ fontSize: '0.78rem', color: 'var(--text-muted)', fontWeight: '700' }}>ÚLTIMA BOLILLA:</div>
                <div style={{ fontSize: '1.2rem', fontWeight: '900', color: 'var(--accent-gold)', fontFamily: 'var(--font-numbers)' }}>
                  {currentBall ? `#${currentBall.num}` : 'En espera'}
                </div>
                <button 
                  className="btn btn-secondary btn-sm"
                  onClick={() => setVideoModeActive(false)}
                  style={{ padding: '3px 8px', fontSize: '0.72rem', marginLeft: '6px' }}
                  title="Volver a la vista del bolillero 3D"
                >
                  <i className="fa-solid fa-arrows-rotate"></i> 3D
                </button>
              </div>
            </div>
          ) : (
            /* Bolilla Central 3D Gigante con Animación Spring */
            <div className="spectator-big-ball-display">
              <div style={{ position: 'absolute', top: '16px', left: '20px', right: '20px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
                  <span className="status-dot offline" style={{ width: '10px', height: '10px', backgroundColor: '#f43f5e', boxShadow: '0 0 12px #f43f5e' }}></span>
                  <span style={{ fontSize: '0.85rem', fontWeight: '800', color: '#fca5a5', letterSpacing: '0.05em' }}>
                    TRANSMISIÓN EN VIVO OFICIAL ({viewersCount} espectadores)
                  </span>
                </div>

                {/* Botones de Control: Mesa de Control (si es organizador) y Audio */}
                <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
                  {videoUrl && (
                    <button 
                      className="btn btn-secondary btn-sm"
                      onClick={() => setVideoModeActive(true)}
                      style={{ padding: '5px 12px', fontSize: '0.8rem', fontWeight: '700', color: 'var(--accent-gold)', border: '1px solid rgba(245, 158, 11, 0.4)' }}
                      title="Ver transmisión de video del bolillero"
                    >
                      <i className="fa-solid fa-video"></i>
                      <span>Ver Video</span>
                    </button>
                  )}

                  <button 
                    className="btn btn-secondary btn-sm" 
                    onClick={handleToggleVoice}
                    title={voiceEnabled ? "Silenciar locutor" : "Activar locutor"}
                    style={{ padding: '5px 10px', fontSize: '0.78rem', display: 'flex', alignItems: 'center', gap: '6px' }}
                  >
                    <i className={`fa-solid ${voiceEnabled ? 'fa-volume-high' : 'fa-volume-xmark'}`} style={{ color: voiceEnabled ? 'var(--accent-teal)' : 'var(--text-dim)' }}></i>
                    <span>{voiceEnabled ? 'Audio ON' : 'Audio OFF'}</span>
                  </button>
                </div>
              </div>

              <div style={{ padding: '24px 0', textAlign: 'center', width: '100%' }}>
                <window.Bolillero 
                  currentBall={currentBall}
                  calledBalls={calledBalls}
                  viewersCount={viewersCount}
                  isSpectator={true}
                  size={150}
                />

                <div style={{ marginTop: '10px', fontSize: '0.9rem', color: 'var(--text-muted)' }}>
                  {currentBall ? (
                    <span>¡Bolilla extraída por el bolillero oficial: <strong>#{currentBall.num}</strong>!</span>
                  ) : (
                    <span>El organizador iniciará la extracción de bolillas en breve.</span>
                  )}
                </div>
              </div>
            </div>
          )}

          {/* Tablero 1 a 90 Plegable */}
          <div className="app-card" style={{ padding: '16px' }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
              <span style={{ fontSize: '0.82rem', fontWeight: '800', color: 'var(--text-muted)', textTransform: 'uppercase' }}>
                Tablero de Control en Vivo
              </span>
              <button 
                className="btn btn-secondary btn-sm"
                onClick={handleToggleMatrix}
                style={{ fontSize: '0.78rem' }}
              >
                <i className="fa-solid fa-table-cells"></i>
                {showMatrix ? 'Ocultar Tablero' : 'Ver Tablero 1-90'}
              </button>
            </div>

            <window.Tablero 
              calledBalls={calledBalls}
              isOpen={showMatrix}
              onToggle={handleToggleMatrix}
            />
          </div>

          {/* ========================================================
              3. TUS CARTONES EN JUEGO (Con Auto-Marcado Elástico)
             ======================================================== */}
          <div className="cards-container">
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: '10px' }}>
              <div>
                <h3 style={{ fontSize: '1.2rem', fontWeight: '800', display: 'flex', alignItems: 'center', gap: '8px', margin: 0 }}>
                  <i className="fa-solid fa-ticket" style={{ color: 'var(--accent-cyan)' }}></i>
                  Tus Cartones en Juego ({userCards.length})
                </h3>
                {userCards.length > 0 && (
                  <div style={{ fontSize: '0.8rem', color: 'var(--accent-gold)', display: 'flex', alignItems: 'center', gap: '6px', marginTop: '4px', fontWeight: '700' }}>
                    <i className="fa-solid fa-print"></i>
                    <span>¿Preferís jugar en papel? Hacé clic en <strong>Descargar PDF (A4)</strong> para imprimir tus cartones.</span>
                  </div>
                )}
              </div>

              {userCards.length > 0 && (
                <div style={{ display: 'flex', gap: '8px', alignItems: 'center', flexWrap: 'wrap' }}>
                  <button 
                    type="button"
                    className="btn btn-secondary btn-sm"
                    onClick={() => {
                      setShowPdfModal(true);
                      if (window.downloadCardsPDF) window.downloadCardsPDF(userCards, userName || 'Espectador');
                    }}
                    style={{
                      display: 'flex',
                      alignItems: 'center',
                      gap: '8px',
                      fontSize: '0.84rem',
                      padding: '8px 14px',
                      fontWeight: '800',
                      color: '#ffffff',
                      background: 'linear-gradient(135deg, #e11d48, #be123c)',
                      border: '1px solid #f43f5e',
                      boxShadow: '0 4px 12px rgba(225, 29, 72, 0.35)',
                      borderRadius: 'var(--radius-md)',
                      cursor: 'pointer'
                    }}
                    title="Descargar tus cartones en PDF imprimible formato A4"
                  >
                    <i className="fa-solid fa-file-pdf" style={{ fontSize: '1rem' }}></i>
                    <span>📄 Descargar PDF Imprimible (A4)</span>
                  </button>
                </div>
              )}
            </div>

            {userCards.length === 0 ? (
              <div style={{ 
                padding: '30px 24px', 
                background: 'rgba(30, 41, 59, 0.45)', 
                borderRadius: 'var(--radius-lg)', 
                border: '1.5px dashed var(--accent-gold)',
                color: 'var(--text-muted)'
              }}>
                <div style={{ textAlign: 'center', marginBottom: '18px' }}>
                  <i className="fa-solid fa-ticket-simple" style={{ fontSize: '2.4rem', marginBottom: '10px', color: 'var(--accent-gold)', display: 'block' }}></i>
                  <div style={{ fontWeight: '900', fontSize: '1.15rem', color: '#ffffff', marginBottom: '4px' }}>
                    Cargar mis Cartones Comprados
                  </div>
                  <div style={{ fontSize: '0.85rem', color: 'var(--text-muted)', maxWidth: '440px', margin: '0 auto', lineHeight: 1.5 }}>
                    Ingresa tu número de teléfono o código de cartón para activar el seguimiento automático en vivo.
                  </div>
                </div>

                <form onSubmit={handleInRoomLookup} style={{ maxWidth: '440px', margin: '0 auto', display: 'flex', flexDirection: 'column', gap: '10px' }}>
                  <div style={{ position: 'relative' }}>
                    <i className="fa-solid fa-phone" style={{ position: 'absolute', left: '14px', top: '50%', transform: 'translateY(-50%)', color: 'var(--accent-gold)' }}></i>
                    <input 
                      type="text"
                      className="input-field"
                      placeholder="Ej: 3872121357, 11 5544 3322 o CR-70196"
                      value={inRoomQuery}
                      onChange={(e) => setInRoomQuery(e.target.value)}
                      style={{ paddingLeft: '40px', width: '100%', fontSize: '0.92rem' }}
                      required
                    />
                  </div>

                  {inRoomMsg && (
                    <div style={{
                      padding: '8px 12px',
                      borderRadius: 'var(--radius-sm)',
                      fontSize: '0.85rem',
                      fontWeight: '700',
                      background: inRoomMsg.type === 'success' ? 'rgba(16, 185, 129, 0.15)' : 'rgba(239, 68, 68, 0.15)',
                      border: inRoomMsg.type === 'success' ? '1px solid #10b981' : '1px solid #ef4444',
                      color: inRoomMsg.type === 'success' ? '#10b981' : '#fca5a5'
                    }}>
                      {inRoomMsg.text}
                    </div>
                  )}

                  <button
                    type="submit"
                    className="btn btn-primary"
                    disabled={inRoomLoading}
                    style={{ padding: '11px 18px', fontWeight: '900', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '8px' }}
                  >
                    <i className={`fa-solid ${inRoomLoading ? 'fa-spinner fa-spin' : 'fa-magnifying-glass'}`}></i>
                    <span>{inRoomLoading ? 'Buscando tus cartones...' : 'Cargar Mis Cartones en Vivo'}</span>
                  </button>
                </form>
              </div>
            ) : (
              userCards.map((card) => (
                <window.CartonView 
                  key={card.id}
                  card={card}
                  calledBalls={calledBalls}
                  isLeaderRadar={false}
                  isUserCard={true}
                />
              ))
            )}
          </div>
        </div>

        {/* Panel Lateral: Seguimiento Privado de Mis Cartones y Estado de la Sala */}
        <div className="live-leaderboard-card" style={{ height: 'fit-content' }}>
          <div className="card-header" style={{ marginBottom: '8px', paddingBottom: '8px' }}>
            <h4 style={{ fontSize: '0.98rem', fontWeight: '800', display: 'flex', alignItems: 'center', gap: '8px' }}>
              <i className="fa-solid fa-chart-simple" style={{ color: 'var(--accent-teal)' }}></i>
              Progreso de Mis Cartones
            </h4>
          </div>

          <div style={{ fontSize: '0.78rem', color: 'var(--text-muted)', marginBottom: '10px' }}>
            {userCards.length === 0 
              ? 'Progreso automático de cartones personales:' 
              : `Seguimiento privado de tus ${userCards.length} ${userCards.length === 1 ? 'cartón' : 'cartones'} en juego:`}
          </div>

          {/* Progreso exclusivo de los cartones del propio espectador */}
          {userCards.length === 0 ? (
            <div style={{ 
              textAlign: 'center', 
              padding: '24px 14px', 
              color: 'var(--text-dim)', 
              fontSize: '0.82rem',
              background: 'rgba(15, 23, 42, 0.4)',
              borderRadius: 'var(--radius-md)',
              border: '1px dashed var(--border-subtle)'
            }}>
              <i className="fa-solid fa-chart-line" style={{ fontSize: '1.6rem', marginBottom: '8px', display: 'block', opacity: 0.3, color: 'var(--accent-teal)' }}></i>
              Aquí verás el progreso automático de tus cartones a medida que salgan las bolillas del bolillero.
            </div>
          ) : (
            <div style={{ display: 'flex', flexDirection: 'column', gap: '10px' }}>
              {userCards.map((card, idx) => {
                const numbers = card.allNumbers && card.allNumbers.length > 0
                  ? card.allNumbers
                  : (card.grid ? card.grid.flat().filter(n => n !== null && n !== undefined) : []);
                const calledSet = new Set(calledBalls.map(b => (typeof b === 'number' ? b : b.num)));
                const matched = numbers.filter(n => calledSet.has(n));
                const missingCount = numbers.length - matched.length;
                const progressPct = numbers.length > 0 ? Math.round((matched.length / numbers.length) * 100) : 0;
                const isBingo = missingCount === 0 && numbers.length > 0;

                return (
                  <div 
                    key={card.id || idx} 
                    style={{ 
                      padding: '10px 12px', 
                      borderRadius: 'var(--radius-md)', 
                      background: 'rgba(15, 23, 42, 0.65)', 
                      border: isBingo ? '1px solid var(--accent-green)' : '1px solid var(--border-subtle)' 
                    }}
                  >
                    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '6px' }}>
                      <span style={{ fontSize: '0.85rem', fontWeight: '800', color: 'var(--text-main)' }}>
                        {card.title || `Cartón #${idx + 1}`}
                      </span>
                      <span style={{ fontSize: '0.82rem', fontWeight: '900', color: isBingo ? 'var(--accent-green)' : 'var(--accent-cyan)' }}>
                        {matched.length} / {numbers.length}
                      </span>
                    </div>

                    <div className="leaderboard-progress-container" style={{ height: '6px', marginBottom: '6px' }}>
                      <div 
                        className="leaderboard-progress-bar" 
                        style={{ 
                          width: `${progressPct}%`, 
                          background: isBingo ? 'var(--accent-green)' : 'linear-gradient(90deg, var(--accent-teal), var(--accent-cyan))' 
                        }}
                      ></div>
                    </div>

                    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', fontSize: '0.74rem', color: 'var(--text-muted)' }}>
                      <span>N° {card.id}</span>
                      <span style={{ color: isBingo ? 'var(--accent-green)' : missingCount <= 3 ? 'var(--accent-gold)' : 'var(--text-dim)', fontWeight: '700' }}>
                        {isBingo ? '👑 ¡BINGO COMPLETO!' : missingCount === 1 ? '🔥 ¡Falta solo 1 número!' : `Faltan ${missingCount} para Bingo`}
                      </span>
                    </div>
                  </div>
                );
              })}
            </div>
          )}

          {/* Estadísticas de la Sala en Vivo */}
          <div style={{ marginTop: '14px', paddingTop: '12px', borderTop: '1px solid var(--border-subtle)' }}>
            <div style={{ fontSize: '0.78rem', fontWeight: '800', color: 'var(--text-muted)', marginBottom: '8px', textTransform: 'uppercase' }}>
              Estado del Sorteo
            </div>

            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '8px', textAlign: 'center' }}>
              <div style={{ background: 'rgba(15, 23, 42, 0.5)', padding: '8px', borderRadius: 'var(--radius-sm)', border: '1px solid var(--border-subtle)' }}>
                <div style={{ fontSize: '0.72rem', color: 'var(--text-muted)' }}>Bolillas</div>
                <strong style={{ fontSize: '1.05rem', color: 'var(--accent-gold)' }}>{calledBalls.length} / 90</strong>
              </div>

              <div style={{ background: 'rgba(15, 23, 42, 0.5)', padding: '8px', borderRadius: 'var(--radius-sm)', border: '1px solid var(--border-subtle)' }}>
                <div style={{ fontSize: '0.72rem', color: 'var(--text-muted)' }}>Espectadores</div>
                <strong style={{ fontSize: '1.05rem', color: '#38bdf8' }}>{viewersCount}</strong>
              </div>
            </div>
          </div>
        </div>
      </div>

      {/* Modal de Descarga y Vista Previa de Cartones en PDF */}
      {showPdfModal && window.CardsPdfModal && (
        <window.CardsPdfModal 
          isOpen={showPdfModal}
          onClose={() => setShowPdfModal(false)}
          cards={userCards}
          playerName={userName || 'Espectador'}
        />
      )}

      {/* Alerta Modal Festiva de Premios */}
      {latestAnnouncement && (
        <div style={{ position: 'fixed', top: 0, left: 0, right: 0, bottom: 0, background: 'rgba(0, 0, 0, 0.82)', backdropFilter: 'blur(6px)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 99999, padding: '20px' }}>
          <div className="app-card" style={{ maxWidth: '520px', width: '100%', textAlign: 'center', padding: '30px 20px', border: '2px solid var(--accent-gold)', animation: 'popIn 0.35s cubic-bezier(0.34, 1.56, 0.64, 1)' }}>
            <div style={{ fontSize: '3rem', marginBottom: '10px' }}>🎉 🏆 👑</div>
            <h2 style={{ fontSize: '1.6rem', fontWeight: '900', color: 'var(--accent-gold)', marginBottom: '8px' }}>
              {latestAnnouncement.title}
            </h2>
            <p style={{ fontSize: '1.05rem', color: 'var(--text-main)', marginBottom: '16px', lineHeight: 1.5 }}>
              {latestAnnouncement.message}
            </p>
            <div style={{ fontSize: '2rem', fontWeight: '900', color: 'var(--accent-green)', fontFamily: 'var(--font-numbers)', marginBottom: '20px' }}>
              {latestAnnouncement.amount}
            </div>
            <button className="btn btn-primary" style={{ padding: '10px 24px', fontWeight: '800' }} onClick={() => setLatestAnnouncement(null)}>
              ¡Entendido, Continuar Viendo!
            </button>
          </div>
        </div>
      )}

      {/* Modal de Configuración y Cambio de Video para Organizador */}
      {showVideoConfigModal && (
        <div style={{ position: 'fixed', top: 0, left: 0, right: 0, bottom: 0, background: 'rgba(0, 0, 0, 0.85)', backdropFilter: 'blur(8px)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 99999, padding: '20px' }}>
          <div className="app-card" style={{ maxWidth: '580px', width: '100%', animation: 'popIn 0.25s ease', border: '1px solid rgba(245, 158, 11, 0.5)' }}>
            <div className="card-header" style={{ marginBottom: '16px' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
                <div style={{ width: '38px', height: '38px', borderRadius: '50%', background: 'rgba(239, 68, 68, 0.2)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#f43f5e', fontSize: '1.2rem' }}>
                  <i className="fa-solid fa-video"></i>
                </div>
                <div>
                  <h3 className="card-title" style={{ margin: 0, fontSize: '1.15rem' }}>Transmisión de Video del Sorteo</h3>
                  <span style={{ fontSize: '0.78rem', color: 'var(--text-muted)' }}>Configurar enlace de transmisión en vivo (YouTube, Facebook, Twitch, etc.)</span>
                </div>
              </div>
              <button className="btn btn-secondary btn-sm" onClick={() => setShowVideoConfigModal(false)}>
                <i className="fa-solid fa-xmark"></i>
              </button>
            </div>

            <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
              <div style={{ background: 'rgba(245, 158, 11, 0.1)', border: '1px solid rgba(245, 158, 11, 0.3)', padding: '10px 14px', borderRadius: 'var(--radius-md)', fontSize: '0.84rem', color: '#fef08a', lineHeight: 1.5 }}>
                <i className="fa-solid fa-lightbulb" style={{ color: 'var(--accent-gold)', marginRight: '6px' }}></i>
                Pega el enlace de tu transmisión o video (<strong>YouTube Live, YouTube, Twitch, Facebook Live o MP4</strong>). Todos los espectadores lo verán sincronizado en su pantalla.
              </div>

              {!isOrganizer && (
                <div>
                  <label style={{ fontSize: '0.86rem', fontWeight: '800', color: '#fca5a5', marginBottom: '6px', display: 'block' }}>
                    Clave de Seguridad de Organizador:
                  </label>
                  <input
                    type="password"
                    className="form-input"
                    placeholder="Ingresa Clave de Organizador"
                    value={adminPinInput}
                    onChange={(e) => {
                      setAdminPinInput(e.target.value);
                      setVideoPinError('');
                    }}
                    style={{ width: '100%', padding: '10px 12px', fontSize: '0.92rem' }}
                  />
                  {videoPinError && (
                    <div style={{ color: '#f87171', fontSize: '0.82rem', marginTop: '4px' }}>
                      {videoPinError}
                    </div>
                  )}
                </div>
              )}

              <div>
                <label style={{ fontSize: '0.86rem', fontWeight: '800', color: 'var(--text-main)', marginBottom: '6px', display: 'block' }}>
                  Enlace del Video o Transmisión:
                </label>
                <input 
                  type="url"
                  className="form-input"
                  placeholder="Ej: https://www.youtube.com/watch?v=... o https://youtu.be/..."
                  value={inputVideoUrl}
                  onChange={(e) => {
                    setInputVideoUrl(e.target.value);
                    setVideoSaveMsg('');
                  }}
                  style={{ width: '100%', padding: '10px 12px', fontSize: '0.92rem' }}
                  autoFocus={isOrganizer}
                />
              </div>

              {/* Vista Previa del Video si es YouTube */}
              {(() => {
                const trimmed = (inputVideoUrl || '').trim();
                const ytMatch = trimmed.match(/(?:youtube\.com\/(?:watch\?v=|live\/|embed\/)|youtu\.be\/)([a-zA-Z0-9_-]{11})/);
                if (ytMatch) {
                  return (
                    <div style={{ borderRadius: 'var(--radius-md)', overflow: 'hidden', border: '1px solid rgba(255, 255, 255, 0.15)', background: '#000' }}>
                      <div style={{ fontSize: '0.75rem', padding: '6px 12px', color: 'var(--accent-green)', background: 'rgba(16, 185, 129, 0.15)', display: 'flex', alignItems: 'center', gap: '6px' }}>
                        <i className="fa-solid fa-circle-check"></i> Vista previa detectada de YouTube
                      </div>
                      <div style={{ position: 'relative', paddingBottom: '45%', height: 0 }}>
                        <iframe
                          src={`https://www.youtube.com/embed/${ytMatch[1]}`}
                          style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', border: 0 }}
                          title="Vista Previa"
                        ></iframe>
                      </div>
                    </div>
                  );
                }
                return null;
              })()}

              {videoSaveMsg && (
                <div style={{ background: 'rgba(16, 185, 129, 0.15)', border: '1px solid var(--accent-green)', padding: '10px', borderRadius: 'var(--radius-md)', color: 'var(--accent-green)', fontSize: '0.85rem', textAlign: 'center', fontWeight: '700' }}>
                  <i className="fa-solid fa-circle-check" style={{ marginRight: '6px' }}></i>
                  {videoSaveMsg}
                </div>
              )}

              {/* Botones de Acción */}
              <div style={{ display: 'flex', flexDirection: 'column', gap: '8px', marginTop: '4px' }}>
                <button 
                  type="button"
                  className="btn btn-primary"
                  disabled={isSavingVideo}
                  style={{ width: '100%', padding: '12px', fontWeight: '800', fontSize: '0.95rem' }}
                  onClick={async () => {
                    if (!isOrganizer) {
                      const pinVal = adminPinInput.trim();
                      if (pinVal !== '1234' && pinVal !== 'LotaMami2026!') {
                        setVideoPinError('Clave de Organizador incorrecta.');
                        return;
                      }
                      try {
                        const adminObj = { role: 'admin', originalRole: 'admin', name: 'Organizador Oficial', adminPin: '1234' };
                        localStorage.setItem('bingo_session_user', JSON.stringify(adminObj));
                      } catch (e) {}
                    }
                    setIsSavingVideo(true);
                    if (room.updateVideoUrl) {
                      await room.updateVideoUrl(inputVideoUrl);
                    }
                    setVideoSaveMsg('¡Enlace de video guardado y transmitido a todos los espectadores!');
                    setIsSavingVideo(false);
                    setTimeout(() => setShowVideoConfigModal(false), 900);
                  }}
                >
                  <i className={`fa-solid ${isSavingVideo ? 'fa-spinner fa-spin' : 'fa-tower-broadcast'}`}></i>
                  <span>Guardar y Transmitir a Espectadores</span>
                </button>

                <div style={{ display: 'flex', gap: '8px' }}>
                  {inputVideoUrl && (
                    <a
                      href={inputVideoUrl}
                      target="_blank"
                      rel="noopener noreferrer"
                      className="btn btn-secondary btn-sm"
                      style={{ flex: 1, padding: '8px', fontSize: '0.82rem', textAlign: 'center', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '6px', textDecoration: 'none' }}
                    >
                      <i className="fa-solid fa-arrow-up-right-from-square"></i> Probar Link
                    </a>
                  )}

                  {videoUrl && (
                    <button
                      type="button"
                      className="btn btn-secondary btn-sm"
                      style={{ flex: 1, padding: '8px', fontSize: '0.82rem', color: '#fca5a5' }}
                      onClick={async () => {
                        const pinVal = adminPinInput.trim();
                        if (!isOrganizer && pinVal !== '1234' && pinVal !== 'LotaMami2026!') {
                          setVideoPinError('Clave de Organizador incorrecta.');
                          return;
                        }
                        if (room.updateVideoUrl) {
                          await room.updateVideoUrl('');
                        }
                        setInputVideoUrl('');
                        setVideoSaveMsg('Transmisión de video desactivada.');
                        setTimeout(() => setShowVideoConfigModal(false), 700);
                      }}
                    >
                      <i className="fa-solid fa-trash-can"></i> Desactivar Transmisión
                    </button>
                  )}
                </div>
              </div>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

window.SpectatorView = SpectatorView;
