import { useEffect, useRef, useState } from 'react';
import { Loader2, Mic, MicOff, Radio } from 'lucide-react';
import { LiveTriviaSession } from '../utils/live-audio';
import { getUserFacingErrorMessage } from '../services/gemini';

const PERSONALITIES = [
  { id: 'game-show', name: 'Classic Game Show Host' },
  { id: 'sarcastic', name: 'Sarcastic Robot' },
  { id: 'pirate', name: 'Salty Pirate' },
  { id: 'posh', name: 'Posh Aristocrat' },
  { id: 'hype', name: 'Hype Beast' },
];

export function LiveTrivia() {
  const [personality, setPersonality] = useState(PERSONALITIES[0]);
  const [sessionState, setSessionState] = useState<'disconnected' | 'connecting' | 'connected'>('disconnected');
  const [statusMessage, setStatusMessage] = useState('Press start to open a live voice session.');
  const [warningMessage, setWarningMessage] = useState<string | null>(null);
  const [targetTranscript, setTargetTranscript] = useState('The host transcript will appear here as soon as Gemini starts talking.');
  const [displayTranscript, setDisplayTranscript] = useState('The host transcript will appear here as soon as Gemini starts talking.');
  const [hostSpeaking, setHostSpeaking] = useState(false);
  const sessionRef = useRef<LiveTriviaSession | null>(null);
  const animationFrameRef = useRef<number | null>(null);
  const speakingWindowRef = useRef<{ startedAt: number; endsAt: number } | null>(null);
  const targetTranscriptRef = useRef(targetTranscript);

  useEffect(() => {
    targetTranscriptRef.current = targetTranscript;
  }, [targetTranscript]);

  useEffect(() => {
    return () => {
      if (animationFrameRef.current !== null) {
        window.cancelAnimationFrame(animationFrameRef.current);
      }
      sessionRef.current?.disconnect();
    };
  }, []);

  const stopCaptionState = () => {
    if (animationFrameRef.current !== null) {
      window.cancelAnimationFrame(animationFrameRef.current);
      animationFrameRef.current = null;
    }
    speakingWindowRef.current = null;
    setHostSpeaking(false);
    setDisplayTranscript((current) => {
      const latestTranscript = targetTranscriptRef.current;
      return latestTranscript && latestTranscript !== current ? latestTranscript : current;
    });
  };

  const startCaptionPlayback = (startedAt: number, endsAt: number) => {
    speakingWindowRef.current = { startedAt, endsAt };
    setHostSpeaking(true);

    const tick = () => {
      const speakingWindow = speakingWindowRef.current;
      if (!speakingWindow) {
        animationFrameRef.current = null;
        return;
      }

      const fullText = targetTranscriptRef.current.trim();
      if (!fullText) {
        animationFrameRef.current = window.requestAnimationFrame(tick);
        return;
      }

      const duration = Math.max(1, speakingWindow.endsAt - speakingWindow.startedAt);
      const progress = Math.max(0, Math.min(1, (Date.now() - speakingWindow.startedAt) / duration));
      const visibleChars = Math.max(1, Math.min(fullText.length, Math.ceil(fullText.length * progress)));
      setDisplayTranscript(fullText.slice(0, visibleChars));

      if (progress >= 1) {
        setDisplayTranscript(fullText);
        animationFrameRef.current = null;
        return;
      }

      animationFrameRef.current = window.requestAnimationFrame(tick);
    };

    if (animationFrameRef.current === null) {
      animationFrameRef.current = window.requestAnimationFrame(tick);
    }
  };

  const toggleConnection = async () => {
    if (sessionState === 'connected' || sessionState === 'connecting') {
      sessionRef.current?.disconnect();
      sessionRef.current = null;
      setStatusMessage('Live session closed.');
      setWarningMessage(null);
      stopCaptionState();
      return;
    }

    const session = new LiveTriviaSession(personality.name, setStatusMessage);
    session.onStateChange = setSessionState;
    session.onTranscriptChange = (text) => {
      if (text) {
        setTargetTranscript(text);
      }
    };
    session.onSpeakingWindowChange = ({ active, startedAt, endsAt }) => {
      if (!active) {
        stopCaptionState();
        return;
      }
      startCaptionPlayback(startedAt, endsAt);
    };
    sessionRef.current = session;
    const pendingText = 'Connecting to Gemini Live. Captions will appear here when the host starts speaking.';
    setTargetTranscript(pendingText);
    setDisplayTranscript(pendingText);
    setWarningMessage(null);

    try {
      await session.connect();
    } catch (error) {
      console.warn(error);
      sessionRef.current = null;
      setSessionState('disconnected');
      setStatusMessage('Failed to connect to live voice.');
      setWarningMessage(getUserFacingErrorMessage(error));
      stopCaptionState();
    }
  };

  return (
    <div className="max-w-2xl mx-auto space-y-8">
      <div className="bg-slate-900 rounded-2xl p-6 border border-slate-800 shadow-xl text-center">
        <div className="w-16 h-16 bg-emerald-500/20 rounded-full flex items-center justify-center mx-auto mb-4">
          <Radio className="w-8 h-8 text-emerald-500" />
        </div>
        <h2 className="text-2xl font-bold text-white mb-2">Live Audio Trivia</h2>
        <p className="text-slate-400 mb-8">
          Talk directly with the host. This mode now uses a short-lived server-issued Gemini token instead of exposing a long-lived API key in the browser.
        </p>

        <div className="max-w-xs mx-auto mb-8 text-left">
          <label className="block text-sm font-medium text-slate-400 mb-1">Host Personality</label>
          <select 
            value={personality.id}
            onChange={(e) => setPersonality(PERSONALITIES.find(p => p.id === e.target.value)!)}
            disabled={sessionState !== 'disconnected'}
            className="w-full bg-slate-950 border border-slate-800 rounded-xl px-4 py-2 text-slate-200 focus:outline-none focus:ring-2 focus:ring-emerald-500 disabled:opacity-50"
          >
            {PERSONALITIES.map(p => (
              <option key={p.id} value={p.id}>{p.name}</option>
            ))}
          </select>
        </div>

        <button
          type="button"
          onClick={() => void toggleConnection()}
          className={`mx-auto flex h-48 w-48 flex-col items-center justify-center gap-4 rounded-full transition-all duration-300 shadow-2xl ${
            sessionState === 'connected'
              ? 'bg-rose-500 shadow-rose-500/20 hover:bg-rose-600'
              : sessionState === 'connecting'
              ? 'bg-slate-800 text-slate-400'
              : 'bg-emerald-500 shadow-emerald-500/20 hover:bg-emerald-600'
          }`}
        >
          {sessionState === 'connecting' ? (
            <Loader2 className="h-12 w-12 animate-spin text-white" />
          ) : sessionState === 'connected' ? (
            <>
              <MicOff className="h-12 w-12 text-white" />
              <span className="text-white font-medium">End Game</span>
            </>
          ) : (
            <>
              <Mic className="h-12 w-12 text-white" />
              <span className="text-white font-medium">Start Playing</span>
            </>
          )}
        </button>

        <p className={`mx-auto max-w-xl text-center text-sm leading-6 ${
          sessionState === 'connected' ? 'text-emerald-300' : 'text-slate-400'
        }`}>
          {statusMessage}
        </p>

        {warningMessage && (
          <div className="mx-auto mt-4 max-w-lg rounded-xl border border-amber-500/30 bg-amber-500/10 px-4 py-3 text-left text-sm text-amber-100">
            {warningMessage}
          </div>
        )}

        <div className={`mx-auto flex max-w-lg flex-col rounded-2xl border px-5 py-5 text-left transition-colors ${
          hostSpeaking
            ? 'border-emerald-400/30 bg-emerald-500/5'
            : 'border-white/10 bg-slate-950/50'
        }`}>
          <div className="mb-3 flex items-center justify-between gap-3">
            <div className="flex items-center gap-3">
              <div className={`flex h-10 w-10 items-center justify-center rounded-full ${hostSpeaking ? 'bg-emerald-500/20 text-emerald-300' : 'bg-slate-800 text-slate-400'}`}>
                <Radio className="h-5 w-5" />
              </div>
              <div>
                <p className="text-sm font-medium text-white">Live captions</p>
                <p className="text-xs text-slate-500">
                  {hostSpeaking ? 'Capturing the host speech in real time.' : 'Waiting for the next spoken Gemini response.'}
                </p>
              </div>
            </div>
            <span className={`rounded-full px-2.5 py-1 text-[11px] font-medium ${hostSpeaking ? 'bg-emerald-500/15 text-emerald-300' : 'bg-slate-800 text-slate-400'}`}>
              {hostSpeaking ? 'Speaking' : 'Idle'}
            </span>
          </div>

          <div className="rounded-xl border border-white/5 bg-slate-900/80 px-4 py-4">
            <p className={`min-h-[5.5rem] text-base leading-8 transition-colors ${
              hostSpeaking ? 'text-white' : 'text-slate-300'
            }`}>
              {displayTranscript}
            </p>
          </div>
        </div>
      </div>
    </div>
  );
}
