/* live-app.jsx — shared hooks, glass UI primitives, search input, demo engine */
/* eslint-disable */

const CFG = window.SONARIUM_CONFIG;

// ────────────────────────────────────────────────────────────
// Hook · useRoom — subscribe to live room state via SonariumSync
// ────────────────────────────────────────────────────────────
function useRoom(code) {
  const roomRef = React.useRef(null);
  const [state, setState] = React.useState(null);
  if (!roomRef.current) roomRef.current = SonariumSync.joinRoom(code);

  React.useEffect(() => {
    return roomRef.current.subscribe(setState);
  }, []);

  return [state, roomRef.current];
}

// ────────────────────────────────────────────────────────────
// Hook · useSpotify — lazy Spotify client + auth state
// ────────────────────────────────────────────────────────────
function useSpotify() {
  const clientRef = React.useRef(null);
  if (!clientRef.current) {
    clientRef.current = SpotifyClient.create({
      clientId: CFG.clientId,
      redirectUri: CFG.redirectUri,
    });
  }
  const [authed, setAuthed] = React.useState(() => clientRef.current.isAuthed());

  // Handle OAuth callback (?code=…)
  React.useEffect(() => {
    if (clientRef.current.isMock) return;
    const url = new URL(location.href);
    if (url.searchParams.has('code')) {
      clientRef.current.handleCallback().then(() => setAuthed(true)).catch(console.error);
    }
  }, []);

  return {
    client: clientRef.current,
    isMock: clientRef.current.isMock,
    authed,
    login:  () => clientRef.current.login(),
    logout: () => { clientRef.current.logout(); setAuthed(false); },
  };
}

// ────────────────────────────────────────────────────────────
// Demo playback engine — auto-advances the queue in demo mode
// ────────────────────────────────────────────────────────────
function useDemoEngine(room, enabled) {
  React.useEffect(() => {
    if (!enabled || !room) return;
    // Seed if empty
    const s = room.state;
    if (s.requests.length === 0) {
      room.seedDemo({
        djName: 'Padre Luis',
        requests: DEMO_REQUESTS,
        nowPlaying: { requestId: DEMO_REQUESTS[0].id, startedAt: Date.now(), durationMs: DEMO_REQUESTS[0].track.durationMs },
        stats: { listeners: 142 },
      });
    }

    // Auto-advance every ~30s in demo (sped up vs real song duration)
    const advance = () => {
      const cur = room.state;
      const playing = cur.requests.find(r => r.status === 'playing');
      const queue = cur.requests.filter(r => r.status === 'queued' || r.status === 'next');
      if (queue.length === 0) return;
      const next = queue[0];
      room.setNowPlaying(next.id);
    };
    const t = setInterval(advance, 30_000);
    return () => clearInterval(t);
  }, [enabled, room]);
}

const DEMO_REQUESTS = [
  { id: 'req_d1', track: { id: 'mk1', uri: 'spotify:mock:mk1', name: 'Vivir Mi Vida',  artists: 'Marc Anthony',  image: null, durationMs: 246_000, _cover: 1 }, from: 'Lucía',     to: 'Promoción 2026',    note: '¡Que nadie se quede sentado esta noche!', anonymous: false, status: 'playing', votes: 21, createdAt: Date.now() - 30_000 },
  { id: 'req_d2', track: { id: 'mk2', uri: 'spotify:mock:mk2', name: 'Color Esperanza',artists: 'Diego Torres',  image: null, durationMs: 245_000, _cover: 2 }, from: 'Padre Luis',to: 'Toda la comunidad', note: 'Para cerrar el curso con esperanza.',     anonymous: false, status: 'next',    votes: 33, createdAt: Date.now() - 20_000 },
  { id: 'req_d3', track: { id: 'mk4', uri: 'spotify:mock:mk4', name: 'Resistiré',      artists: 'Dúo Dinámico',  image: null, durationMs: 217_000, _cover: 3 }, from: 'Abuela Carmen',to: 'Las voluntarias',note: 'Por todas las que no se rinden.',       anonymous: false, status: 'queued',  votes: 12, createdAt: Date.now() - 18_000 },
  { id: 'req_d4', track: { id: 'mk8', uri: 'spotify:mock:mk8', name: 'Eres Tú',        artists: 'Mocedades',     image: null, durationMs: 191_000, _cover: 1 }, from: 'Coro FSJA', to: 'Los profesores',    note: 'Gracias por este curso.',                 anonymous: false, status: 'queued',  votes: 18, createdAt: Date.now() - 15_000 },
  { id: 'req_d5', track: { id: 'mka', uri: 'spotify:mock:mka', name: 'Bailando',       artists: 'Enrique Iglesias', image: null, durationMs: 245_000, _cover: 3 }, from: 'Sofía',     to: 'Mis amigas',        note: 'La nuestra de siempre.',                  anonymous: false, status: 'pending', votes: 7,  createdAt: Date.now() - 10_000 },
  { id: 'req_d6', track: { id: 'mk5', uri: 'spotify:mock:mk5', name: 'Wake Me Up',     artists: 'Avicii',        image: null, durationMs: 247_000, _cover: 4 }, from: 'Jorge',     to: 'Hermanos pequeños', note: 'Por las noches de campamento.',          anonymous: false, status: 'pending', votes: 9,  createdAt: Date.now() - 6_000 },
  { id: 'req_d7', track: { id: 'mk7', uri: 'spotify:mock:mk7', name: 'Ojalá',          artists: 'Silvio Rodríguez', image: null, durationMs: 295_000, _cover: 0 }, from: 'Anónimo',   to: 'M.',                note: '— ya sabes para quién es.',               anonymous: true,  status: 'pending', votes: 4,  createdAt: Date.now() - 2_000 },
];

// ────────────────────────────────────────────────────────────
// Track artwork — uses Spotify image URL or falls back to Cover
// ────────────────────────────────────────────────────────────
function TrackArt({ track, size = 56, radius = 10 }) {
  if (track?.image) {
    return (
      <img src={track.image} alt="" style={{
        width: size, height: size, borderRadius: radius, objectFit: 'cover',
        flexShrink: 0, boxShadow: '0 4px 10px rgba(0,0,0,0.3)',
      }}/>
    );
  }
  return <Cover seed={track?._cover ?? 0} size={size} radius={radius}/>;
}

// ────────────────────────────────────────────────────────────
// Spotify search typeahead
// ────────────────────────────────────────────────────────────
function TrackSearch({ spotify, onPick, placeholder = 'Busca canción o artista…' }) {
  const [q, setQ] = React.useState('');
  const [results, setResults] = React.useState([]);
  const [open, setOpen] = React.useState(false);
  const [loading, setLoading] = React.useState(false);
  const debounce = React.useRef();

  React.useEffect(() => {
    clearTimeout(debounce.current);
    if (q.trim().length < 1) { setResults([]); return; }
    setLoading(true);
    debounce.current = setTimeout(async () => {
      try {
        const r = await spotify.search(q);
        setResults(r);
      } catch (e) { console.warn(e); }
      finally { setLoading(false); }
    }, 220);
    return () => clearTimeout(debounce.current);
  }, [q]);

  // Show some defaults when focused with empty input
  React.useEffect(() => {
    if (open && !q.trim()) {
      spotify.search('').then(setResults).catch(() => {});
    }
  }, [open]);

  return (
    <div style={{ position: 'relative' }}>
      <div style={{ position: 'relative' }}>
        <div style={{
          position: 'absolute', left: 14, top: '50%', transform: 'translateY(-50%)',
          color: 'rgba(255,255,255,0.5)', pointerEvents: 'none',
        }}>{Icon.search(16)}</div>
        <input
          className="glass-input"
          value={q}
          onChange={(e) => { setQ(e.target.value); setOpen(true); }}
          onFocus={() => setOpen(true)}
          onBlur={() => setTimeout(() => setOpen(false), 160)}
          placeholder={placeholder}
          style={{ paddingLeft: 42 }}
        />
        {loading && <div style={{
          position: 'absolute', right: 14, top: '50%', transform: 'translateY(-50%)',
          width: 14, height: 14, border: '1.5px solid rgba(255,255,255,0.2)',
          borderTopColor: 'var(--gold-500)', borderRadius: '50%',
          animation: 'spin 0.8s linear infinite',
        }}/>}
      </div>
      {open && results.length > 0 && (
        <div className="glass" style={{
          position: 'absolute', top: 'calc(100% + 6px)', left: 0, right: 0,
          maxHeight: 320, overflowY: 'auto', padding: 6, zIndex: 50,
        }}>
          {results.map(t => (
            <div key={t.id}
              onMouseDown={(e) => { e.preventDefault(); onPick(t); setOpen(false); setQ(''); setResults([]); }}
              style={{
                display: 'flex', alignItems: 'center', gap: 10, padding: '8px 8px',
                borderRadius: 10, cursor: 'pointer',
                transition: 'background 0.12s',
              }}
              onMouseEnter={(e) => e.currentTarget.style.background = 'rgba(255,255,255,0.07)'}
              onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}
            >
              <TrackArt track={t} size={40} radius={7}/>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 13.5, fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
                  {t.name}
                </div>
                <div style={{ fontSize: 12, color: 'rgba(255,255,255,0.55)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
                  {t.artists}
                </div>
              </div>
              <div className="mono" style={{ fontSize: 11, color: 'rgba(255,255,255,0.4)', flexShrink: 0 }}>
                {Math.floor(t.durationMs / 60000)}:{String(Math.floor(t.durationMs % 60000 / 1000)).padStart(2, '0')}
              </div>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

// ────────────────────────────────────────────────────────────
// Toasts
// ────────────────────────────────────────────────────────────
const ToastCtx = React.createContext(() => {});
function useToast() { return React.useContext(ToastCtx); }
function ToastProvider({ children }) {
  const [items, setItems] = React.useState([]);
  const push = React.useCallback((msg, tone = 'default') => {
    const id = Date.now() + Math.random();
    setItems((it) => [...it, { id, msg, tone }]);
    setTimeout(() => setItems((it) => it.filter(x => x.id !== id)), 3200);
  }, []);
  return (
    <ToastCtx.Provider value={push}>
      {children}
      <div style={{
        position: 'fixed', bottom: 28, left: '50%', transform: 'translateX(-50%)',
        display: 'flex', flexDirection: 'column', gap: 8, zIndex: 1000,
        pointerEvents: 'none',
      }}>
        {items.map(t => (
          <div key={t.id} className="glass" style={{
            padding: '12px 18px', fontSize: 14, color: '#fff',
            border: t.tone === 'error' ? '0.5px solid #c64' : 'none',
            animation: 'toastIn 0.25s ease-out',
          }}>{t.msg}</div>
        ))}
      </div>
    </ToastCtx.Provider>
  );
}

// Inject one-time animations
if (!document.getElementById('live-anim')) {
  const s = document.createElement('style');
  s.id = 'live-anim';
  s.textContent = `
    @keyframes spin { to { transform: rotate(360deg); } }
    @keyframes toastIn { from { transform: translateY(8px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
    @keyframes fadeIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
    .fade-in { animation: fadeIn 0.35s ease-out; }
  `;
  document.head.appendChild(s);
}

// ────────────────────────────────────────────────────────────
// Aurora background wrapper for full-bleed routes
// ────────────────────────────────────────────────────────────
function AuroraScreen({ children }) {
  return (
    <div style={{ minHeight: '100vh', position: 'relative', overflow: 'hidden' }}>
      <div className="aurora"><div className="orb-mid"/></div>
      <div className="grain" style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}/>
      <div style={{ position: 'relative', zIndex: 1, minHeight: '100vh' }}>{children}</div>
    </div>
  );
}


// Format helpers
const fmt = {
  mmss: (ms) => `${Math.floor(ms / 60000)}:${String(Math.floor(ms % 60000 / 1000)).padStart(2, '0')}`,
  ago: (ts) => {
    const d = Math.floor((Date.now() - ts) / 1000);
    if (d < 10) return 'ahora';
    if (d < 60) return `hace ${d}s`;
    if (d < 3600) return `hace ${Math.floor(d / 60)}m`;
    return `hace ${Math.floor(d / 3600)}h`;
  },
};

// ────────────────────────────────────────────────────────────
// Room code generator — two random Spanish words joined by -
// ────────────────────────────────────────────────────────────
function generateRoomCode() {
  const words = [
    'LUNA', 'SOL', 'MAR', 'RIO', 'MONTE', 'PRADO', 'CIELO', 'FUEGO', 'AGUA', 'VIENTO',
    'VERDE', 'ROJO', 'AZUL', 'BLANCO', 'DORADO', 'PLATA', 'CORAL', 'OCRE', 'NIEVE', 'BRUMA',
    'ROCA', 'BOSQUE', 'CAMPO', 'VALLE', 'ALBA', 'DUNA', 'PINO', 'ROBLE', 'SAUCE', 'NIEBLA',
  ];
  const pick = () => words[Math.floor(Math.random() * words.length)];
  let a, b;
  do { a = pick(); b = pick(); } while (a === b);
  return `${a}-${b}`;
}

Object.assign(window, {
  useRoom, useSpotify, useDemoEngine,
  TrackArt, TrackSearch, ToastProvider, useToast,
  AuroraScreen, fmt, CFG,
  generateRoomCode,
});
