import { useState, useEffect, useRef, useCallback } from 'react';
import './watch-together.css';

// ── Types ──

interface RoomInfo {
  id: string;
  name: string;
  hostName: string;
  memberCount: number;
  memberNames: string[];
  hasPassword: boolean;
  playing: boolean;
}

interface RoomState {
  id: string;
  name: string;
  hostId: string;
  members: Array<{ id: string; name: string }>;
  currentVideo: { url: string; title: string } | null;
  playing: boolean;
  currentTime: number;
  queue: Array<{ url: string; title: string; addedBy: string; watched: boolean }>;
}

interface JoinModal {
  roomId: string;
  roomName: string;
  password: string;
  error: string | null;
}

// ── Helpers ──

function formatTime(s: number): string {
  const sec = Math.floor(s);
  const h = Math.floor(sec / 3600);
  const m = Math.floor((sec % 3600) / 60);
  const ss = sec % 60;
  if (h > 0) return `${h}:${String(m).padStart(2, '0')}:${String(ss).padStart(2, '0')}`;
  return `${m}:${String(ss).padStart(2, '0')}`;
}

function parseVideoUrl(url: string): { type: 'youtube'; videoId: string } | { type: 'dailymotion'; videoId: string } | { type: 'direct'; url: string } | null {
  const ytMatch = url.match(/(?:youtube\.com\/(?:watch\?v=|embed\/|shorts\/)|youtu\.be\/)([a-zA-Z0-9_-]{11})/);
  if (ytMatch) return { type: 'youtube', videoId: ytMatch[1] };
  const dmMatch = url.match(/(?:dailymotion\.com\/video\/|dai\.ly\/)([a-zA-Z0-9]+)/);
  if (dmMatch) return { type: 'dailymotion', videoId: dmMatch[1] };
  if (/\.(mp4|webm|ogg)(\?|$)/i.test(url) || url.startsWith('http')) return { type: 'direct', url };
  return null;
}

declare global {
  interface Window {
    YT: any;
    onYouTubeIframeAPIReady: (() => void) | undefined;
  }
}

// ── Component ──

export default function WatchTogetherTab({ data }: { data: any }) {
  // ── State ──
  const [rooms, setRooms] = useState<RoomInfo[]>([]);
  const [userName, setUserName] = useState(() => localStorage.getItem('wt_name') || '');
  const [roomName, setRoomName] = useState('');
  const [roomPassword, setRoomPassword] = useState('');
  const [currentRoom, setCurrentRoom] = useState<RoomState | null>(null);
  const [joinModal, setJoinModal] = useState<JoinModal | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [queueUrl, setQueueUrl] = useState('');
  const [volume, setVolume] = useState(() => {
    const v = localStorage.getItem('wt_volume');
    return v ? parseFloat(v) : 1;
  });
  const [isFullscreen, setIsFullscreen] = useState(false);
  const [duration, setDuration] = useState(0);
  const [currentTime, setCurrentTime] = useState(0);
  const [playerError, setPlayerError] = useState<string | null>(null);
  const [addingToQueue, setAddingToQueue] = useState(false);
  const [chatMessages, setChatMessages] = useState<Array<{ sender: string; text: string; timestamp: number }>>([]);
  const [chatInput, setChatInput] = useState('');
  const [votes, setVotes] = useState<{ skip: number; pause: number; total: number; needed: number } | null>(null);
  const [syncStatus, setSyncStatus] = useState<'synced' | 'drifting' | 'desynced'>('synced');
  const [showChat, setShowChat] = useState(true);
  const [ytQuality, setYtQuality] = useState<string>(() => localStorage.getItem('wt_yt_quality') || 'hd1080');

  // ── Refs ──
  const wsRef = useRef<WebSocket | null>(null);
  const clientIdRef = useRef<string>('');
  const reconnectTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const reconnectDelayRef = useRef(1000);
  const currentRoomRef = useRef<RoomState | null>(null);
  const roomContainerRef = useRef<HTMLDivElement | null>(null);

  // Player refs
  const ytPlayerRef = useRef<any>(null);
  const videoRef = useRef<HTMLVideoElement | null>(null);
  const playerContainerRef = useRef<HTMLDivElement | null>(null);
  const currentVideoTypeRef = useRef<'youtube' | 'direct' | 'dailymotion' | null>(null);
  const ytReadyRef = useRef(false);
  const seekingRef = useRef(false);
  const timeUpdateRef = useRef<ReturnType<typeof setInterval> | null>(null);
  const chatEndRef = useRef<HTMLDivElement | null>(null);

  // Quality ref (for YT player callbacks)
  const ytQualityRef = useRef(ytQuality);

  // Dailymotion refs
  const dmPlayerRef = useRef<HTMLIFrameElement | null>(null);
  const dmReadyRef = useRef(false);
  const dmTimeRef = useRef(0);
  const dmDurationRef = useRef(0);

  // Mirror state to refs
  useEffect(() => { currentRoomRef.current = currentRoom; }, [currentRoom]);

  const isHost = currentRoom != null && clientIdRef.current === currentRoom.hostId;

  // ── Save quality + apply to running player ──
  useEffect(() => {
    ytQualityRef.current = ytQuality;
    localStorage.setItem('wt_yt_quality', ytQuality);
    if (ytPlayerRef.current && typeof ytPlayerRef.current.setPlaybackQuality === 'function') {
      ytPlayerRef.current.setPlaybackQuality(ytQuality);
    }
  }, [ytQuality]);

  // ── SSE data ──
  useEffect(() => {
    if (data?.rooms) {
      setRooms(data.rooms);
    }
  }, [data]);

  // ── Auto-scroll chat ──
  useEffect(() => {
    chatEndRef.current?.scrollIntoView({ behavior: 'smooth' });
  }, [chatMessages]);

  // ── Join via link ──
  useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    const roomId = params.get('wt');
    if (roomId && userName.trim()) {
      // Delay to let WS connect first
      const timer = setTimeout(() => joinRoom(roomId), 1500);
      return () => clearTimeout(timer);
    }
  }, []);

  // ── Save name ──
  useEffect(() => {
    if (userName) localStorage.setItem('wt_name', userName);
  }, [userName]);

  // ── Save volume ──
  useEffect(() => {
    localStorage.setItem('wt_volume', String(volume));
    if (ytPlayerRef.current && typeof ytPlayerRef.current.setVolume === 'function') {
      ytPlayerRef.current.setVolume(volume * 100);
    }
    if (videoRef.current) {
      videoRef.current.volume = volume;
    }
    if (dmPlayerRef.current?.contentWindow && currentVideoTypeRef.current === 'dailymotion') {
      dmPlayerRef.current.contentWindow.postMessage(`volume?volume=${volume}`, 'https://www.dailymotion.com');
    }
  }, [volume]);

  // ── YouTube IFrame API ──
  useEffect(() => {
    if (window.YT) { ytReadyRef.current = true; return; }
    const tag = document.createElement('script');
    tag.src = 'https://www.youtube.com/iframe_api';
    document.head.appendChild(tag);
    const prev = window.onYouTubeIframeAPIReady;
    window.onYouTubeIframeAPIReady = () => {
      ytReadyRef.current = true;
      if (prev) prev();
    };
  }, []);

  // ── WS send ──
  const wsSend = useCallback((d: Record<string, any>) => {
    if (wsRef.current?.readyState === WebSocket.OPEN) {
      wsRef.current.send(JSON.stringify(d));
    }
  }, []);

  // ── Get current time from active player ──
  const getCurrentTime = useCallback((): number | null => {
    if (currentVideoTypeRef.current === 'youtube' && ytPlayerRef.current && typeof ytPlayerRef.current.getCurrentTime === 'function') {
      return ytPlayerRef.current.getCurrentTime();
    }
    if (currentVideoTypeRef.current === 'direct' && videoRef.current) {
      return videoRef.current.currentTime;
    }
    if (currentVideoTypeRef.current === 'dailymotion') {
      return dmTimeRef.current;
    }
    return null;
  }, []);

  // ── Get duration from active player ──
  const getDuration = useCallback((): number => {
    if (currentVideoTypeRef.current === 'youtube' && ytPlayerRef.current && typeof ytPlayerRef.current.getDuration === 'function') {
      return ytPlayerRef.current.getDuration() || 0;
    }
    if (currentVideoTypeRef.current === 'direct' && videoRef.current) {
      return videoRef.current.duration || 0;
    }
    if (currentVideoTypeRef.current === 'dailymotion') {
      return dmDurationRef.current;
    }
    return 0;
  }, []);

  // ── Destroy player ──
  const destroyPlayer = useCallback(() => {
    if (ytPlayerRef.current) {
      try { ytPlayerRef.current.destroy(); } catch {}
      ytPlayerRef.current = null;
    }
    if (videoRef.current) {
      videoRef.current.pause();
      videoRef.current.removeAttribute('src');
      videoRef.current.load();
    }
    if (dmPlayerRef.current) {
      dmPlayerRef.current.src = '';
      dmReadyRef.current = false;
      dmTimeRef.current = 0;
      dmDurationRef.current = 0;
    }
    currentVideoTypeRef.current = null;
    if (timeUpdateRef.current) {
      clearInterval(timeUpdateRef.current);
      timeUpdateRef.current = null;
    }
  }, []);

  // ── Load video ──
  const loadVideo = useCallback((url: string) => {
    destroyPlayer();
    setPlayerError(null);
    const parsed = parseVideoUrl(url);
    if (!parsed) return;

    if (parsed.type === 'youtube') {
      currentVideoTypeRef.current = 'youtube';
      if (!ytReadyRef.current || !playerContainerRef.current) return;

      // Create a fresh div for YT player
      const container = playerContainerRef.current;
      const ytDiv = document.createElement('div');
      ytDiv.id = 'wt-yt-player-' + Date.now();
      container.innerHTML = '';
      container.appendChild(ytDiv);

      ytPlayerRef.current = new window.YT.Player(ytDiv.id, {
        videoId: parsed.videoId,
        playerVars: { autoplay: 1, controls: 0, modestbranding: 1, rel: 0 },
        events: {
          onReady: (ev: any) => {
            ev.target.setVolume(volume * 100);
            ev.target.setPlaybackQuality(ytQualityRef.current);
            setDuration(ev.target.getDuration() || 0);
            // Time update interval
            timeUpdateRef.current = setInterval(() => {
              if (ytPlayerRef.current && typeof ytPlayerRef.current.getCurrentTime === 'function') {
                setCurrentTime(ytPlayerRef.current.getCurrentTime());
                setDuration(ytPlayerRef.current.getDuration() || 0);
              }
            }, 500);
          },
          onStateChange: (ev: any) => {
            if (ev.data === window.YT.PlayerState.ENDED) {
              const room = currentRoomRef.current;
              if (room && clientIdRef.current === room.hostId) {
                wsSend({ type: 'skip' });
              }
            }
          },
          onError: (ev: any) => {
            const code = ev.data;
            // 101 or 150 = embedding disabled by video owner
            // 100 = video not found
            // 5 = HTML5 player error
            if (code === 101 || code === 150) {
              setPlayerError('Embedding deaktiviert \u2014 Video kann nur auf YouTube angesehen werden.');
            } else if (code === 100) {
              setPlayerError('Video nicht gefunden oder entfernt.');
            } else {
              setPlayerError('Wiedergabefehler \u2014 Video wird \u00FCbersprungen.');
            }
            // Auto-skip after 3 seconds if host
            setTimeout(() => {
              const room = currentRoomRef.current;
              if (room && clientIdRef.current === room.hostId) {
                wsSend({ type: 'skip' });
              }
            }, 3000);
          },
        },
      });
    } else if (parsed.type === 'dailymotion') {
      currentVideoTypeRef.current = 'dailymotion';
      if (dmPlayerRef.current) {
        dmPlayerRef.current.src = `https://www.dailymotion.com/embed/video/${parsed.videoId}?api=postMessage&autoplay=1&controls=0&mute=0&queue-enable=0`;
      }
    } else {
      currentVideoTypeRef.current = 'direct';
      if (videoRef.current) {
        videoRef.current.src = parsed.url;
        videoRef.current.volume = volume;
        videoRef.current.play().catch(() => {});
      }
    }
  }, [destroyPlayer, volume, wsSend]);

  // ── HTML5 video ended handler ──
  useEffect(() => {
    const video = videoRef.current;
    if (!video) return;
    const onEnded = () => {
      const room = currentRoomRef.current;
      if (room && clientIdRef.current === room.hostId) {
        wsSend({ type: 'skip' });
      }
    };
    const onTimeUpdate = () => {
      setCurrentTime(video.currentTime);
      setDuration(video.duration || 0);
    };
    video.addEventListener('ended', onEnded);
    video.addEventListener('timeupdate', onTimeUpdate);
    return () => {
      video.removeEventListener('ended', onEnded);
      video.removeEventListener('timeupdate', onTimeUpdate);
    };
  }, [wsSend]);

  // ── Dailymotion postMessage listener ──
  useEffect(() => {
    const handler = (ev: MessageEvent) => {
      if (ev.origin !== 'https://www.dailymotion.com') return;
      if (typeof ev.data !== 'string') return;
      const params = new URLSearchParams(ev.data);
      const method = params.get('method');
      const value = params.get('value');

      if (method === 'timeupdate' && value) {
        const t = parseFloat(value);
        dmTimeRef.current = t;
        setCurrentTime(t);
      } else if (method === 'durationchange' && value) {
        const d = parseFloat(value);
        dmDurationRef.current = d;
        setDuration(d);
      } else if (method === 'ended') {
        const room = currentRoomRef.current;
        if (room && clientIdRef.current === room.hostId) {
          wsSend({ type: 'skip' });
        }
      } else if (method === 'apiready') {
        dmReadyRef.current = true;
        if (dmPlayerRef.current?.contentWindow) {
          dmPlayerRef.current.contentWindow.postMessage(`volume?volume=${volume}`, 'https://www.dailymotion.com');
        }
      }
    };
    window.addEventListener('message', handler);
    return () => window.removeEventListener('message', handler);
  }, [wsSend, volume]);

  // ── WS message handler ──
  const handleWsMessageRef = useRef<(msg: any) => void>(() => {});
  handleWsMessageRef.current = (msg: any) => {
    switch (msg.type) {
      case 'welcome':
        clientIdRef.current = msg.clientId;
        if (msg.rooms) setRooms(msg.rooms);
        break;

      case 'room_created': {
        const r = msg.room;
        setCurrentRoom({
          id: r.id,
          name: r.name,
          hostId: r.hostId,
          members: r.members || [],
          currentVideo: r.currentVideo || null,
          playing: r.playing || false,
          currentTime: r.currentTime || 0,
          queue: r.queue || [],
        });
        break;
      }

      case 'room_joined': {
        const r = msg.room;
        setCurrentRoom({
          id: r.id,
          name: r.name,
          hostId: r.hostId,
          members: r.members || [],
          currentVideo: r.currentVideo || null,
          playing: r.playing || false,
          currentTime: r.currentTime || 0,
          queue: r.queue || [],
        });
        if (r.currentVideo?.url) {
          setTimeout(() => loadVideo(r.currentVideo.url), 100);
        }
        break;
      }

      case 'playback_state': {
        const room = currentRoomRef.current;
        if (!room) break;

        const newVideo = msg.currentVideo;
        const prevUrl = room.currentVideo?.url;

        // 1. Video URL changed → load new video
        if (newVideo?.url && newVideo.url !== prevUrl) {
          loadVideo(newVideo.url);
        } else if (!newVideo && prevUrl) {
          destroyPlayer();
        }

        // 2. Playing mismatch → play or pause
        if (currentVideoTypeRef.current === 'youtube' && ytPlayerRef.current) {
          const playerState = ytPlayerRef.current.getPlayerState?.();
          if (msg.playing && playerState !== window.YT?.PlayerState?.PLAYING) {
            ytPlayerRef.current.playVideo?.();
          } else if (!msg.playing && playerState === window.YT?.PlayerState?.PLAYING) {
            ytPlayerRef.current.pauseVideo?.();
          }
        } else if (currentVideoTypeRef.current === 'direct' && videoRef.current) {
          if (msg.playing && videoRef.current.paused) {
            videoRef.current.play().catch(() => {});
          } else if (!msg.playing && !videoRef.current.paused) {
            videoRef.current.pause();
          }
        } else if (currentVideoTypeRef.current === 'dailymotion' && dmPlayerRef.current?.contentWindow) {
          if (msg.playing) {
            dmPlayerRef.current.contentWindow.postMessage('play', 'https://www.dailymotion.com');
          } else {
            dmPlayerRef.current.contentWindow.postMessage('pause', 'https://www.dailymotion.com');
          }
        }

        // 3. Drift correction: if |localTime - serverTime| > 2 → seek
        if (msg.currentTime !== undefined && !seekingRef.current) {
          const localTime = getCurrentTime();
          if (localTime !== null && Math.abs(localTime - msg.currentTime) > 2) {
            if (currentVideoTypeRef.current === 'youtube' && ytPlayerRef.current) {
              ytPlayerRef.current.seekTo?.(msg.currentTime, true);
            } else if (currentVideoTypeRef.current === 'direct' && videoRef.current) {
              videoRef.current.currentTime = msg.currentTime;
            } else if (currentVideoTypeRef.current === 'dailymotion' && dmPlayerRef.current?.contentWindow) {
              dmPlayerRef.current.contentWindow.postMessage(`seek?to=${msg.currentTime}`, 'https://www.dailymotion.com');
            }
          }
        }

        // Sync status
        if (msg.currentTime !== undefined) {
          const localTime = getCurrentTime();
          if (localTime !== null) {
            const drift = Math.abs(localTime - msg.currentTime);
            if (drift < 1.5) setSyncStatus('synced');
            else if (drift < 5) setSyncStatus('drifting');
            else setSyncStatus('desynced');
          }
        }

        setCurrentRoom(prev => prev ? {
          ...prev,
          currentVideo: newVideo || null,
          playing: msg.playing,
          currentTime: msg.currentTime ?? prev.currentTime,
        } : prev);
        break;
      }

      case 'queue_updated':
        setCurrentRoom(prev => prev ? { ...prev, queue: msg.queue } : prev);
        break;

      case 'members_updated':
        setCurrentRoom(prev => prev ? { ...prev, members: msg.members, hostId: msg.hostId } : prev);
        break;

      case 'vote_updated':
        setVotes(msg.votes);
        break;

      case 'chat':
        setChatMessages(prev => {
          const next = [...prev, { sender: msg.sender, text: msg.text, timestamp: msg.timestamp }];
          return next.length > 100 ? next.slice(-100) : next;
        });
        break;

      case 'chat_history':
        setChatMessages(msg.messages || []);
        break;

      case 'error':
        if (msg.code === 'WRONG_PASSWORD') {
          setJoinModal(prev => prev ? { ...prev, error: msg.message } : prev);
        } else {
          setError(msg.message);
        }
        break;
    }
  };

  // ── WebSocket connect ──
  const connectWs = useCallback(() => {
    if (wsRef.current && (wsRef.current.readyState === WebSocket.OPEN || wsRef.current.readyState === WebSocket.CONNECTING)) return;

    const proto = location.protocol === 'https:' ? 'wss' : 'ws';
    const ws = new WebSocket(`${proto}://${location.host}/ws/watch-together`);
    wsRef.current = ws;

    ws.onopen = () => { reconnectDelayRef.current = 1000; };

    ws.onmessage = (ev) => {
      let msg: any;
      try { msg = JSON.parse(ev.data); } catch { return; }
      handleWsMessageRef.current(msg);
    };

    ws.onclose = () => {
      if (wsRef.current === ws) {
        wsRef.current = null;
      }
      if (currentRoomRef.current) {
        reconnectTimerRef.current = setTimeout(() => {
          reconnectDelayRef.current = Math.min(reconnectDelayRef.current * 2, 10000);
          connectWs();
        }, reconnectDelayRef.current);
      }
    };

    ws.onerror = () => { ws.close(); };
  }, []);

  // ── Create room ──
  const createRoom = useCallback(() => {
    if (!userName.trim()) { setError('Bitte gib einen Namen ein.'); return; }
    if (!roomName.trim()) { setError('Bitte gib einen Raumnamen ein.'); return; }
    setError(null);
    connectWs();

    const startTime = Date.now();
    const waitForWs = () => {
      if (wsRef.current?.readyState === WebSocket.OPEN) {
        wsSend({
          type: 'create_room',
          name: roomName.trim(),
          userName: userName.trim(),
          password: roomPassword.trim() || undefined,
        });
      } else if (Date.now() - startTime > 10000) {
        setError('Verbindung zum Server fehlgeschlagen.');
      } else {
        setTimeout(waitForWs, 100);
      }
    };
    waitForWs();
  }, [userName, roomName, roomPassword, connectWs, wsSend]);

  // ── Join room ──
  const joinRoom = useCallback((roomId: string, password?: string) => {
    if (!userName.trim()) { setError('Bitte gib einen Namen ein.'); return; }
    setError(null);
    connectWs();

    const startTime = Date.now();
    const waitForWs = () => {
      if (wsRef.current?.readyState === WebSocket.OPEN) {
        wsSend({
          type: 'join_room',
          userName: userName.trim(),
          roomId,
          password: password?.trim() || undefined,
        });
      } else if (Date.now() - startTime > 10000) {
        setError('Verbindung zum Server fehlgeschlagen.');
      } else {
        setTimeout(waitForWs, 100);
      }
    };
    waitForWs();
  }, [userName, connectWs, wsSend]);

  // ── Leave room ──
  const leaveRoom = useCallback(() => {
    wsSend({ type: 'leave_room' });
    destroyPlayer();
    setCurrentRoom(null);
    setQueueUrl('');
    setDuration(0);
    setCurrentTime(0);
    setChatMessages([]);
    setVotes(null);
    setSyncStatus('synced');
  }, [wsSend, destroyPlayer]);

  // ── Add to queue ──
  const addToQueue = useCallback(async () => {
    const url = queueUrl.trim();
    if (!url) return;
    setQueueUrl('');
    setAddingToQueue(true);

    let title = '';
    try {
      const resp = await fetch(`/api/watch-together/video-info?url=${encodeURIComponent(url)}`);
      if (resp.ok) {
        const data = await resp.json();
        title = data.title || '';
      }
    } catch { /* use URL as fallback */ }

    wsSend({ type: 'add_to_queue', url, title: title || undefined });
    setAddingToQueue(false);
  }, [queueUrl, wsSend]);

  // ── Send chat ──
  const sendChat = useCallback(() => {
    const text = chatInput.trim();
    if (!text) return;
    setChatInput('');
    wsSend({ type: 'chat_message', text });
  }, [chatInput, wsSend]);

  // ── Vote callbacks ──
  const voteSkip = useCallback(() => {
    wsSend({ type: 'vote_skip' });
  }, [wsSend]);

  const votePause = useCallback(() => {
    wsSend({ type: 'vote_pause' });
  }, [wsSend]);

  // ── Clear watched ──
  const clearWatched = useCallback(() => {
    wsSend({ type: 'clear_watched' });
  }, [wsSend]);

  // ── Copy room link ──
  const copyRoomLink = useCallback(() => {
    if (!currentRoom) return;
    const url = `${window.location.origin}${window.location.pathname}?wt=${currentRoom.id}`;
    navigator.clipboard.writeText(url).catch(() => {});
  }, [currentRoom]);

  // ── Remove from queue ──
  const removeFromQueue = useCallback((index: number) => {
    wsSend({ type: 'remove_from_queue', index });
  }, [wsSend]);

  // ── Playback controls (host only) ──
  const togglePlay = useCallback(() => {
    const room = currentRoomRef.current;
    if (!room) return;
    wsSend({ type: room.playing ? 'pause' : 'resume' });
  }, [wsSend]);

  const skip = useCallback(() => {
    wsSend({ type: 'skip' });
  }, [wsSend]);

  const seek = useCallback((time: number) => {
    seekingRef.current = true;
    wsSend({ type: 'seek', time });
    // Seek locally immediately
    if (currentVideoTypeRef.current === 'youtube' && ytPlayerRef.current) {
      ytPlayerRef.current.seekTo?.(time, true);
    } else if (currentVideoTypeRef.current === 'direct' && videoRef.current) {
      videoRef.current.currentTime = time;
    } else if (currentVideoTypeRef.current === 'dailymotion' && dmPlayerRef.current?.contentWindow) {
      dmPlayerRef.current.contentWindow.postMessage(`seek?to=${time}`, 'https://www.dailymotion.com');
    }
    setCurrentTime(time);
    setTimeout(() => { seekingRef.current = false; }, 3000);
  }, [wsSend]);

  // ── Host time reporting ──
  useEffect(() => {
    if (!isHost || !currentRoom?.playing) return;
    const iv = setInterval(() => {
      const time = getCurrentTime();
      if (time !== null) wsSend({ type: 'report_time', time });
    }, 2000);
    return () => clearInterval(iv);
  }, [isHost, currentRoom?.playing, wsSend, getCurrentTime]);

  // ── Fullscreen ──
  const toggleFullscreen = useCallback(() => {
    const el = roomContainerRef.current;
    if (!el) return;
    if (!document.fullscreenElement) el.requestFullscreen().catch(() => {});
    else document.exitFullscreen().catch(() => {});
  }, []);

  useEffect(() => {
    const handler = () => setIsFullscreen(!!document.fullscreenElement);
    document.addEventListener('fullscreenchange', handler);
    return () => document.removeEventListener('fullscreenchange', handler);
  }, []);

  // ── beforeunload + pagehide ──
  useEffect(() => {
    const beforeUnload = (e: BeforeUnloadEvent) => {
      if (currentRoomRef.current) e.preventDefault();
    };
    const pageHide = () => {
      if (clientIdRef.current) {
        navigator.sendBeacon('/api/watch-together/disconnect', JSON.stringify({ clientId: clientIdRef.current }));
      }
    };
    window.addEventListener('beforeunload', beforeUnload);
    window.addEventListener('pagehide', pageHide);
    return () => {
      window.removeEventListener('beforeunload', beforeUnload);
      window.removeEventListener('pagehide', pageHide);
    };
  }, []);

  // ── Cleanup on unmount ──
  useEffect(() => {
    return () => {
      destroyPlayer();
      if (wsRef.current) wsRef.current.close();
      if (reconnectTimerRef.current) clearTimeout(reconnectTimerRef.current);
    };
  }, [destroyPlayer]);

  // ── Join modal submit ──
  const submitJoinModal = useCallback(() => {
    if (!joinModal) return;
    if (!joinModal.password.trim()) {
      setJoinModal(prev => prev ? { ...prev, error: 'Passwort eingeben.' } : prev);
      return;
    }
    const { roomId, password } = joinModal;
    setJoinModal(null);
    joinRoom(roomId, password);
  }, [joinModal, joinRoom]);

  // ── Tile click ──
  const handleTileClick = useCallback((room: RoomInfo) => {
    if (room.hasPassword) {
      setJoinModal({ roomId: room.id, roomName: room.name, password: '', error: null });
    } else {
      joinRoom(room.id);
    }
  }, [joinRoom]);

  // ── Render: Room View ──
  if (currentRoom) {
    const hostMember = currentRoom.members.find(m => m.id === currentRoom.hostId);
    return (
      <div className="wt-room-overlay" ref={roomContainerRef}>
        <div className="wt-room-header">
          <div className="wt-room-header-left">
            <span className="wt-room-name">{currentRoom.name}</span>
            <span className="wt-room-members">{currentRoom.members.length} Mitglieder</span>
            {hostMember && <span className="wt-host-badge">Host: {hostMember.name}</span>}
          </div>
          <div className="wt-room-header-right">
            <div className={`wt-sync-dot wt-sync-${syncStatus}`} title={syncStatus === 'synced' ? 'Synchron' : syncStatus === 'drifting' ? 'Leichte Verzögerung' : 'Nicht synchron'} />
            <button className="wt-header-btn" onClick={copyRoomLink} title="Link kopieren">Link</button>
            <button className="wt-header-btn" onClick={() => setShowChat(c => !c)} title={showChat ? 'Chat ausblenden' : 'Chat einblenden'}>Chat</button>
            <button className="wt-fullscreen-btn" onClick={toggleFullscreen} title={isFullscreen ? 'Vollbild verlassen' : 'Vollbild'}>
              {isFullscreen ? '\u2716' : '\u26F6'}
            </button>
            <button className="wt-leave-btn" onClick={leaveRoom}>Verlassen</button>
          </div>
        </div>

        <div className="wt-room-body">
          <div className="wt-player-section">
            <div className="wt-player-wrap">
              <div ref={playerContainerRef} className="wt-yt-container" style={currentVideoTypeRef.current === 'youtube' ? {} : { display: 'none' }} />
              <video
                ref={videoRef}
                className="wt-video-element"
                style={currentVideoTypeRef.current === 'direct' ? {} : { display: 'none' }}
                playsInline
              />
              <iframe
                ref={dmPlayerRef}
                className="wt-dm-container"
                style={currentVideoTypeRef.current === 'dailymotion' ? {} : { display: 'none' }}
                allow="autoplay; fullscreen"
                allowFullScreen
              />
              {playerError && (
                <div className="wt-player-error">
                  <div className="wt-error-icon">{'\u26A0\uFE0F'}</div>
                  <p>{playerError}</p>
                  {currentRoom.currentVideo?.url && (
                    <a
                      className="wt-yt-link"
                      href={currentRoom.currentVideo.url}
                      target="_blank"
                      rel="noopener noreferrer"
                    >
                      Auf YouTube &ouml;ffnen &#8599;
                    </a>
                  )}
                  <p className="wt-skip-info">Wird in 3 Sekunden &uuml;bersprungen...</p>
                </div>
              )}
              {!currentRoom.currentVideo && (
                <div className="wt-player-placeholder">
                  <div className="wt-placeholder-icon">{'\uD83C\uDFAC'}</div>
                  <p>Fuege ein Video zur Warteschlange hinzu</p>
                </div>
              )}
            </div>

            <div className="wt-controls">
              <button className="wt-ctrl-btn" onClick={togglePlay} disabled={!currentRoom.currentVideo} title={currentRoom.playing ? 'Pause' : 'Abspielen'}>
                {currentRoom.playing ? '\u23F8' : '\u25B6'}
              </button>
              <button className="wt-ctrl-btn wt-next-btn" onClick={skip} disabled={!currentRoom.currentVideo && currentRoom.queue.length === 0} title="Nächstes Video">
                {'\u23ED'} Weiter
              </button>
              <input
                className="wt-seek"
                type="range"
                min={0}
                max={duration || 0}
                step={0.5}
                value={currentTime}
                onChange={e => seek(parseFloat(e.target.value))}
                disabled={!currentRoom.currentVideo}
              />
              <span className="wt-time">{formatTime(currentTime)} / {formatTime(duration)}</span>
              <div className="wt-volume">
                <span className="wt-volume-icon">{volume === 0 ? '\uD83D\uDD07' : volume < 0.5 ? '\uD83D\uDD09' : '\uD83D\uDD0A'}</span>
                <input
                  className="wt-volume-slider"
                  type="range"
                  min={0}
                  max={1}
                  step={0.01}
                  value={volume}
                  onChange={e => setVolume(parseFloat(e.target.value))}
                />
              </div>
              {currentVideoTypeRef.current === 'youtube' && (
                <select
                  className="wt-quality-select"
                  value={ytQuality}
                  onChange={e => setYtQuality(e.target.value)}
                  title="Videoqualit&auml;t"
                >
                  <option value="highres">4K+</option>
                  <option value="hd2160">2160p</option>
                  <option value="hd1440">1440p</option>
                  <option value="hd1080">1080p</option>
                  <option value="hd720">720p</option>
                  <option value="large">480p</option>
                  <option value="medium">360p</option>
                  <option value="small">240p</option>
                </select>
              )}
            </div>
          </div>

          <div className="wt-queue-panel">
            <div className="wt-queue-header">
              <span>Warteschlange ({currentRoom.queue.length})</span>
              {currentRoom.queue.some(q => q.watched) && (
                <button className="wt-queue-clear-btn" onClick={clearWatched} title="Gesehene entfernen">Gesehene entfernen</button>
              )}
            </div>
            <div className="wt-queue-list">
              {currentRoom.queue.length === 0 ? (
                <div className="wt-queue-empty">Keine Videos in der Warteschlange</div>
              ) : (
                currentRoom.queue.map((item, i) => {
                  const isCurrent = currentRoom.currentVideo?.url === item.url;
                  return (
                    <div
                      key={i}
                      className={`wt-queue-item${isCurrent ? ' playing' : ''}${item.watched && !isCurrent ? ' watched' : ''} clickable`}
                      onClick={() => wsSend({ type: 'play_video', index: i })}
                      title="Klicken zum Abspielen"
                    >
                      <div className="wt-queue-item-info">
                        {item.watched && !isCurrent && <span className="wt-queue-item-check">{'\u2713'}</span>}
                        {item.url.match(/youtu/) && (
                          <img
                            className="wt-queue-thumb"
                            src={`https://img.youtube.com/vi/${item.url.match(/(?:youtube\.com\/(?:watch\?v=|embed\/|shorts\/)|youtu\.be\/)([a-zA-Z0-9_-]{11})/)?.[1]}/default.jpg`}
                            alt=""
                          />
                        )}
                        <div className="wt-queue-item-text">
                          <div className="wt-queue-item-title">{item.title || item.url}</div>
                          <div className="wt-queue-item-by">{item.addedBy}</div>
                        </div>
                      </div>
                      {isHost && (
                        <button className="wt-queue-item-remove" onClick={(e) => { e.stopPropagation(); removeFromQueue(i); }} title="Entfernen">
                          {'\u00D7'}
                        </button>
                      )}
                    </div>
                  );
                })
              )}
            </div>
            <div className="wt-queue-add">
              <input
                className="wt-input wt-queue-input"
                placeholder="Video-URL eingeben"
                value={queueUrl}
                onChange={e => setQueueUrl(e.target.value)}
                onKeyDown={e => { if (e.key === 'Enter') addToQueue(); }}
              />
              <button className="wt-btn wt-queue-add-btn" onClick={addToQueue} disabled={addingToQueue}>
                {addingToQueue ? 'Laden...' : 'Hinzufuegen'}
              </button>
            </div>
          </div>

          {showChat && (
            <div className="wt-chat-panel">
              <div className="wt-chat-header">Chat</div>
              <div className="wt-chat-messages">
                {chatMessages.length === 0 ? (
                  <div className="wt-chat-empty">Noch keine Nachrichten</div>
                ) : (
                  chatMessages.map((msg, i) => (
                    <div key={i} className="wt-chat-msg">
                      <span className="wt-chat-sender">{msg.sender}</span>
                      <span className="wt-chat-text">{msg.text}</span>
                    </div>
                  ))
                )}
                <div ref={chatEndRef} />
              </div>
              <div className="wt-chat-input-row">
                <input
                  className="wt-input wt-chat-input"
                  placeholder="Nachricht..."
                  value={chatInput}
                  onChange={e => setChatInput(e.target.value)}
                  onKeyDown={e => { if (e.key === 'Enter') sendChat(); }}
                  maxLength={500}
                />
                <button className="wt-btn wt-chat-send-btn" onClick={sendChat}>Senden</button>
              </div>
            </div>
          )}
        </div>
      </div>
    );
  }

  // ── Render: Lobby ──
  return (
    <div className="wt-container">
      {error && (
        <div className="wt-error">
          {error}
          <button className="wt-error-dismiss" onClick={() => setError(null)}>{'\u00D7'}</button>
        </div>
      )}

      <div className="wt-topbar">
        <input
          className="wt-input wt-input-name"
          placeholder="Dein Name"
          value={userName}
          onChange={e => setUserName(e.target.value)}
        />
        <input
          className="wt-input wt-input-room"
          placeholder="Raumname"
          value={roomName}
          onChange={e => setRoomName(e.target.value)}
        />
        <input
          className="wt-input wt-input-password"
          type="password"
          placeholder="Passwort (optional)"
          value={roomPassword}
          onChange={e => setRoomPassword(e.target.value)}
        />
        <button className="wt-btn" onClick={createRoom}>Raum erstellen</button>
      </div>

      {rooms.length === 0 ? (
        <div className="wt-empty">
          <div className="wt-empty-icon">{'\uD83C\uDFAC'}</div>
          <h3>Keine aktiven Raeume</h3>
          <p>Erstelle einen Raum, um gemeinsam Videos zu schauen.</p>
        </div>
      ) : (
        <div className="wt-grid">
          {rooms.map(room => (
            <div key={room.id} className="wt-tile" onClick={() => handleTileClick(room)}>
              <div className="wt-tile-preview">
                <span className="wt-tile-icon">{'\uD83C\uDFAC'}</span>
                <span className="wt-tile-members">{'\uD83D\uDC65'} {room.memberCount}</span>
                {room.hasPassword && <span className="wt-tile-lock">{'\uD83D\uDD12'}</span>}
                {room.playing && <span className="wt-tile-playing">{'\u25B6'}</span>}
              </div>
              <div className="wt-tile-info">
                <div className="wt-tile-meta">
                  <div className="wt-tile-name">{room.name}</div>
                  <div className="wt-tile-host">{room.hostName}</div>
                </div>
                {room.memberNames && room.memberNames.length > 0 && (
                  <div className="wt-tile-members-list">
                    {room.memberNames.slice(0, 5).join(', ')}
                    {room.memberNames.length > 5 && ` +${room.memberNames.length - 5}`}
                  </div>
                )}
              </div>
            </div>
          ))}
        </div>
      )}

      {joinModal && (
        <div className="wt-modal-overlay" onClick={() => setJoinModal(null)}>
          <div className="wt-modal" onClick={e => e.stopPropagation()}>
            <h3>{joinModal.roomName}</h3>
            <p>Raum-Passwort</p>
            {joinModal.error && <div className="wt-modal-error">{joinModal.error}</div>}
            <input
              className="wt-input"
              type="password"
              placeholder="Passwort"
              value={joinModal.password}
              onChange={e => setJoinModal(prev => prev ? { ...prev, password: e.target.value, error: null } : prev)}
              onKeyDown={e => { if (e.key === 'Enter') submitJoinModal(); }}
              autoFocus
            />
            <div className="wt-modal-actions">
              <button className="wt-modal-cancel" onClick={() => setJoinModal(null)}>Abbrechen</button>
              <button className="wt-btn" onClick={submitJoinModal}>Beitreten</button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
