'use client';

import 'src/styles/livekit-theme.css';
import 'src/styles/livekit-components.css';

import { createPortal } from 'react-dom';
import { isTrackReference } from '@livekit/components-core';
import { useRouter, useSearchParams } from 'next/navigation';
import { useRef, useState, useEffect, Component } from 'react';
import { Track, RoomEvent, VideoPresets } from 'livekit-client';
import {
  useTracks,
  LiveKitRoom,
  useStartAudio,
  useRoomContext,
  VideoConference,
  ParticipantTile,
  RoomAudioRenderer,
  ConnectionStateToast,
} from '@livekit/components-react';

import { getLesson } from 'src/utils/dashboard-api';
import { getOrCreateLessonBoard } from 'src/utils/board-api';
import { getLiveKitConfig, participantConnected } from 'src/utils/livekit-api';

import { ExitLessonModal } from 'src/sections/video-call/livekit/exit-lesson-modal';

import { useAuthContext } from 'src/auth/hooks';

// ----------------------------------------------------------------------

const PRESET_2K = {
  resolution: { width: 2560, height: 1440 },
  encoding: { maxBitrate: 6_000_000, maxFramerate: 30 },
};

const CHAT_PANEL_WIDTH = 420;

const LS_AUDIO_PLAYBACK_ALLOWED = 'videoConference_audioPlaybackAllowed';
const LS_AUDIO_ENABLED = 'videoConference_audioEnabled';
const LS_VIDEO_ENABLED = 'videoConference_videoEnabled';
const SS_PREJOIN_DONE = 'livekit_prejoin_done';

// ----------------------------------------------------------------------

function isLiveKitLayoutError(error) {
  const msg = error instanceof Error ? error.message : String(error);
  return (
    msg.includes('Element not part of the array') ||
    msg.includes('updatePages') ||
    msg.includes('_placeholder not in')
  );
}

class LiveKitLayoutErrorBoundary extends Component {
  constructor(props) {
    super(props);
    this.state = { error: null, recoverKey: 0 };
  }

  static getDerivedStateFromError(error) {
    return { error };
  }

  componentDidCatch(error) {
    if (isLiveKitLayoutError(error)) {
      window.setTimeout(() => {
        this.setState((s) => ({ error: null, recoverKey: s.recoverKey + 1 }));
      }, 100);
    }
  }

  render() {
    const { error, recoverKey } = this.state;
    const { children } = this.props;
    if (error && !isLiveKitLayoutError(error)) throw error;
    if (error) return <div style={{ flex: 1, background: '#000', minHeight: 200 }} />;
    // eslint-disable-next-line react/jsx-no-useless-fragment
    return <>{children}</>;
  }
}

// ----------------------------------------------------------------------

function getSavedAudioVideo() {
  try {
    const rawA = localStorage.getItem(LS_AUDIO_ENABLED);
    const rawV = localStorage.getItem(LS_VIDEO_ENABLED);
    return { audio: rawA !== 'false', video: rawV !== 'false' };
  } catch {
    return { audio: true, video: true };
  }
}

function getInitialShowPreJoin(sp) {
  try {
    if (typeof window !== 'undefined' && sessionStorage.getItem(SS_PREJOIN_DONE) === '1') return false;
    return sp.get('skip_prejoin') !== '1';
  } catch {
    return true;
  }
}

function getTokenMetadata(token) {
  if (!token) return {};
  try {
    const parts = token.split('.');
    if (parts.length !== 3) return {};
    const payload = JSON.parse(atob(parts[1].replace(/-/g, '+').replace(/_/g, '/')));
    const { metadata } = payload;
    if (!metadata || typeof metadata !== 'string') return {};
    const parsed = JSON.parse(metadata);
    return {
      board_id: parsed?.board_id ?? undefined,
      is_mentor: parsed?.is_mentor === true,
    };
  } catch {
    return {};
  }
}

// ----------------------------------------------------------------------

function StartAudioOverlay() {
  const room = useRoomContext();
  const { mergedProps, canPlayAudio } = useStartAudio({ room, props: {} });
  const [dismissed, setDismissed] = useState(() => {
    try {
      return localStorage.getItem(LS_AUDIO_PLAYBACK_ALLOWED) === 'true';
    } catch {
      return false;
    }
  });

  useEffect(() => {
    if (canPlayAudio) {
      try {
        localStorage.setItem(LS_AUDIO_PLAYBACK_ALLOWED, 'true');
      } catch { /* ignore */ }
    }
  }, [canPlayAudio]);

  if (canPlayAudio || dismissed) return null;

  const handleClick = () => {
    try {
      localStorage.setItem(LS_AUDIO_PLAYBACK_ALLOWED, 'true');
    } catch { /* ignore */ }
    setDismissed(true);
    mergedProps.onClick?.();
  };

  return (
    <div style={{ position: 'fixed', inset: 0, zIndex: 9999, background: 'rgba(0,0,0,0.75)', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 24, padding: 24 }}>
      <p style={{ color: '#fff', fontSize: 18, textAlign: 'center', margin: 0 }}>Чтобы слышать собеседника, разрешите воспроизведение звука</p>
      <button type="button" onClick={handleClick} style={{ padding: '16px 32px', fontSize: 18, fontWeight: 600, borderRadius: 12, border: 'none', background: '#1976d2', color: '#fff', cursor: 'pointer' }}>
        🔊 Разрешить звук
      </button>
    </div>
  );
}

// ----------------------------------------------------------------------

function RemoteParticipantPiP({ chatOpen }) {
  const tracks = useTracks([Track.Source.Camera, Track.Source.ScreenShare], { onlySubscribed: true });
  const remoteRef = tracks.find((ref) => isTrackReference(ref) && ref.participant && !ref.participant.isLocal);
  if (!remoteRef || !isTrackReference(remoteRef)) return null;
  return (
    <div style={{ position: 'fixed', bottom: 24, right: chatOpen ? CHAT_PANEL_WIDTH + 24 : 24, width: 280, height: 158, zIndex: 10000, borderRadius: 12, overflow: 'hidden', boxShadow: '0 8px 32px rgba(0,0,0,0.5)', border: '2px solid rgba(255,255,255,0.2)', background: '#000' }}>
      <ParticipantTile trackRef={remoteRef} />
    </div>
  );
}

// ----------------------------------------------------------------------

function WhiteboardIframe({ boardId, showingBoard }) {
  const excalidrawUrl = process.env.NEXT_PUBLIC_EXCALIDRAW_URL || '';
  const iframeRef = useRef(null);

  useEffect(() => {
    if (!excalidrawUrl || !boardId) return undefined;
    const container = iframeRef.current;
    if (!container) return undefined;
    const iframe = document.createElement('iframe');
    iframe.src = `${excalidrawUrl}?boardId=${boardId}`;
    iframe.style.cssText = 'width:100%;height:100%;border:none;';
    iframe.allow = 'camera; microphone; fullscreen';
    container.innerHTML = '';
    container.appendChild(iframe);
    return () => {
      container.innerHTML = '';
    };
  }, [boardId, excalidrawUrl]);

  if (!excalidrawUrl) {
    return (
      <div style={{ width: '100%', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff', background: '#111' }}>
        Доска не настроена (NEXT_PUBLIC_EXCALIDRAW_URL)
      </div>
    );
  }

  return (
    <div
      ref={iframeRef}
      style={{ width: '100%', height: '100%', pointerEvents: showingBoard ? 'auto' : 'none' }}
    />
  );
}

// ----------------------------------------------------------------------

function PreJoinScreen({ onJoin, onCancel }) {
  const [audioEnabled, setAudioEnabled] = useState(true);
  const [videoEnabled, setVideoEnabled] = useState(true);
  const videoRef = useRef(null);

  useEffect(() => {
    const saved = getSavedAudioVideo();
    setAudioEnabled(saved.audio);
    setVideoEnabled(saved.video);
  }, []);

  useEffect(() => {
    if (!videoEnabled) return undefined;
    let stream = null;
    navigator.mediaDevices
      .getUserMedia({ video: { width: { ideal: 2560 }, height: { ideal: 1440 }, frameRate: { ideal: 30 } }, audio: false })
      .then((s) => {
        stream = s;
        if (videoRef.current) videoRef.current.srcObject = s;
      })
      .catch(() => {});
    return () => {
      stream?.getTracks().forEach((t) => t.stop());
    };
  }, [videoEnabled]);

  const handleJoin = () => {
    try {
      localStorage.setItem(LS_AUDIO_ENABLED, String(audioEnabled));
      localStorage.setItem(LS_VIDEO_ENABLED, String(videoEnabled));
    } catch { /* ignore */ }
    onJoin(audioEnabled, videoEnabled);
  };

  return (
    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', background: 'linear-gradient(135deg, #f5f7fa 0%, #e4e8ec 100%)' }}>
      <div style={{ background: '#fff', borderRadius: 20, maxWidth: 520, width: '100%', overflow: 'hidden', boxShadow: '0 8px 32px rgba(0,0,0,0.1)' }}>
        <div style={{ background: 'linear-gradient(135deg, #1976d2 0%, #7c4dff 100%)', padding: 24, color: '#fff' }}>
          <h1 style={{ fontSize: 22, fontWeight: 700, margin: 0 }}>Настройки перед входом</h1>
          <p style={{ margin: '8px 0 0 0', opacity: 0.9 }}>Настройте камеру и микрофон</p>
        </div>
        <div style={{ padding: 24 }}>
          <div style={{ marginBottom: 24, background: '#000', borderRadius: 12, aspectRatio: '16/9', overflow: 'hidden' }}>
            {videoEnabled ? (
              <video ref={videoRef} autoPlay playsInline muted style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
            ) : (
              <div style={{ width: '100%', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', flexDirection: 'column', color: '#666', minHeight: 120 }}>
                <span style={{ fontSize: 48 }}>📵</span>
                <p style={{ margin: 8 }}>Камера выключена</p>
              </div>
            )}
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 12, marginBottom: 24 }}>
            {[
              { label: 'Микрофон', enabled: audioEnabled, toggle: () => setAudioEnabled((v) => !v) },
              { label: 'Камера', enabled: videoEnabled, toggle: () => setVideoEnabled((v) => !v) },
            ].map(({ label, enabled, toggle }) => (
              <div key={label} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: 16, background: '#f5f5f5', borderRadius: 12 }}>
                <span>{label}</span>
                <button onClick={toggle} type="button" style={{ padding: '8px 20px', borderRadius: 10, border: 'none', background: enabled ? '#1976d2' : '#888', color: '#fff', cursor: 'pointer' }}>
                  {enabled ? 'Выключить' : 'Включить'}
                </button>
              </div>
            ))}
          </div>
          <div style={{ display: 'flex', gap: 12 }}>
            <button type="button" onClick={onCancel} style={{ flex: 1, padding: '14px 24px', borderRadius: 14, border: '1px solid #ddd', background: 'transparent', cursor: 'pointer' }}>Отмена</button>
            <button type="button" onClick={handleJoin} style={{ flex: 1, padding: '14px 24px', borderRadius: 14, border: 'none', background: '#1976d2', color: '#fff', fontWeight: 600, cursor: 'pointer' }}>
              📹 Войти в конференцию
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}

// ----------------------------------------------------------------------

function RoomContent({ lessonId, boardId, boardLoading, showBoard, setShowBoard }) {
  const room = useRoomContext();
  const router = useRouter();
  const { user } = useAuthContext();
  const [showPlatformChat, setShowPlatformChat] = useState(false);
  const [showExitModal, setShowExitModal] = useState(false);
  const [showNavMenu, setShowNavMenu] = useState(false);

  useEffect(() => {
    const onConnected = () => {
      if (room.name || lessonId) {
        participantConnected({ roomName: room.name || '', lessonId: lessonId ?? undefined }).catch(() => {});
      }
    };
    room.on(RoomEvent.Connected, onConnected);
    if (room.state === 'connected' && (room.name || lessonId)) {
      participantConnected({ roomName: room.name || '', lessonId: lessonId ?? undefined }).catch(() => {});
    }
    return () => {
      room.off(RoomEvent.Connected, onConnected);
    };
  }, [room, lessonId]);

  // Inject exit and burger buttons into LiveKit control bar
  useEffect(() => {
    if (showBoard) return undefined;
    const id = setTimeout(() => {
      const bar = document.querySelector('.lk-control-bar');
      if (!bar) return;
      if (!bar.querySelector('.lk-burger-button')) {
        const burger = document.createElement('button');
        burger.type = 'button';
        burger.className = 'lk-button lk-burger-button';
        burger.title = 'Меню';
        burger.textContent = '☰';
        burger.addEventListener('click', () => window.dispatchEvent(new CustomEvent('livekit-burger-click')));
        bar.insertBefore(burger, bar.firstChild);
      }
      if (!bar.querySelector('.lk-custom-exit-button')) {
        const btn = document.createElement('button');
        btn.type = 'button';
        btn.className = 'lk-button lk-custom-exit-button';
        btn.title = 'Выйти';
        btn.textContent = '🚪';
        btn.addEventListener('click', () => window.dispatchEvent(new CustomEvent('livekit-exit-click')));
        bar.appendChild(btn);
      }
    }, 800);
    return () => clearTimeout(id);
  }, [showBoard]);

  useEffect(() => {
    const handler = () => setShowNavMenu((v) => !v);
    window.addEventListener('livekit-burger-click', handler);
    return () => window.removeEventListener('livekit-burger-click', handler);
  }, []);

  useEffect(() => {
    const handler = () => {
      if (user?.role === 'mentor') {
        setShowExitModal(true);
      } else {
        room.disconnect();
      }
    };
    window.addEventListener('livekit-exit-click', handler);
    return () => window.removeEventListener('livekit-exit-click', handler);
  }, [user?.role, room]);

  // Save audio/video state on track events
  useEffect(() => {
    const lp = room.localParticipant;
    if (!lp) return undefined;
    const save = () => {
      try {
        localStorage.setItem(LS_AUDIO_ENABLED, String(lp.isMicrophoneEnabled));
        localStorage.setItem(LS_VIDEO_ENABLED, String(lp.isCameraEnabled));
      } catch { /* ignore */ }
    };
    const onMuted = (pub, participant) => {
      if (participant?.sid !== lp.sid) return;
      if (pub?.source === Track.Source.Microphone) {
        try { localStorage.setItem(LS_AUDIO_ENABLED, 'false'); } catch { /* ignore */ }
      } else if (pub?.source === Track.Source.Camera) {
        try { localStorage.setItem(LS_VIDEO_ENABLED, 'false'); } catch { /* ignore */ }
      } else {
        save();
      }
    };
    const onUnmuted = (pub, participant) => {
      if (participant?.sid !== lp.sid) return;
      if (pub?.source === Track.Source.Microphone) {
        try { localStorage.setItem(LS_AUDIO_ENABLED, 'true'); } catch { /* ignore */ }
      } else if (pub?.source === Track.Source.Camera) {
        try { localStorage.setItem(LS_VIDEO_ENABLED, 'true'); } catch { /* ignore */ }
      } else {
        save();
      }
    };
    room.on(RoomEvent.TrackMuted, onMuted);
    room.on(RoomEvent.TrackUnmuted, onUnmuted);
    room.on(RoomEvent.LocalTrackPublished, save);
    save();
    return () => {
      room.off(RoomEvent.TrackMuted, onMuted);
      room.off(RoomEvent.TrackUnmuted, onUnmuted);
      room.off(RoomEvent.LocalTrackPublished, save);
    };
  }, [room]);

  const sidebarStyle = {
    position: 'fixed',
    right: showPlatformChat ? CHAT_PANEL_WIDTH + 16 : 16,
    top: '50%',
    transform: 'translateY(-50%)',
    display: 'flex',
    flexDirection: 'column',
    gap: 8,
    padding: 8,
    background: 'rgba(0,0,0,0.7)',
    borderRadius: 12,
    zIndex: 10001,
  };

  const iconBtn = (active, disabled, title, icon, onClick) => (
    <button
      type="button"
      onClick={onClick}
      disabled={disabled}
      title={title}
      style={{
        width: 48,
        height: 48,
        borderRadius: 12,
        border: 'none',
        background: active ? '#1976d2' : 'rgba(255,255,255,0.2)',
        color: '#fff',
        cursor: disabled ? 'not-allowed' : 'pointer',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        fontSize: 20,
        opacity: disabled ? 0.6 : 1,
      }}
    >
      {icon}
    </button>
  );

  return (
    <div style={{ height: '100vh', position: 'relative', display: 'flex' }}>
      <StartAudioOverlay />
      <div style={{ flex: 1, position: 'relative', background: '#000' }}>
        <div style={{ position: 'absolute', inset: 0, zIndex: showBoard ? 0 : 1 }}>
          <LiveKitLayoutErrorBoundary>
            <VideoConference chatMessageFormatter={(message) => message} />
          </LiveKitLayoutErrorBoundary>
        </div>
      </div>

      {typeof document !== 'undefined' &&
        createPortal(
          <>
            {showBoard && <RemoteParticipantPiP chatOpen={showPlatformChat} />}
            {showBoard && (
              <button
                type="button"
                onClick={() => setShowNavMenu((v) => !v)}
                style={{ position: 'fixed', left: 16, bottom: 64, width: 48, height: 48, borderRadius: 12, border: 'none', background: 'rgba(0,0,0,0.7)', color: '#fff', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 10002, fontSize: 20 }}
                title="Меню"
              >
                ☰
              </button>
            )}
            {showNavMenu && (
              // eslint-disable-next-line jsx-a11y/no-static-element-interactions
              <div
                onClick={() => setShowNavMenu(false)}
                onKeyDown={(e) => e.key === 'Escape' && setShowNavMenu(false)}
                style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.4)', zIndex: 10003, backdropFilter: 'blur(4px)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}
              >
                {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
                <div onClick={(e) => e.stopPropagation()} onKeyDown={(e) => e.stopPropagation()} style={{ background: '#fff', borderRadius: 16, padding: 24, minWidth: 240 }}>
                  <button type="button" onClick={() => { setShowNavMenu(false); router.push('/dashboard'); }} style={{ width: '100%', padding: '12px 16px', border: 'none', background: 'none', textAlign: 'left', cursor: 'pointer', fontSize: 16, borderRadius: 8 }}>
                    🏠 На главную
                  </button>
                  <button type="button" onClick={() => setShowNavMenu(false)} style={{ width: '100%', padding: '12px 16px', border: 'none', background: 'none', textAlign: 'left', cursor: 'pointer', fontSize: 16, borderRadius: 8 }}>
                    ✕ Закрыть
                  </button>
                </div>
              </div>
            )}
            <div style={sidebarStyle}>
              {iconBtn(!showBoard, false, 'Камера', '📹', () => setShowBoard(false))}
              {iconBtn(showBoard, !boardId || boardLoading, boardLoading ? 'Загрузка доски...' : !boardId ? 'Доска недоступна' : 'Доска', boardLoading ? '⏳' : '🎨', () => boardId && !boardLoading && setShowBoard(true))}
              {lessonId != null && iconBtn(showPlatformChat, false, 'Чат', '💬', () => setShowPlatformChat((v) => !v))}
            </div>
          </>,
          document.body
        )}

      <ExitLessonModal
        isOpen={showExitModal}
        lessonId={lessonId}
        onClose={() => setShowExitModal(false)}
        onExit={() => room.disconnect()}
      />
    </div>
  );
}

// ----------------------------------------------------------------------

export function VideoCallView() {
  const router = useRouter();
  const searchParams = useSearchParams();
  const accessToken = searchParams.get('token');
  const lessonIdParam = searchParams.get('lesson_id');
  const { user } = useAuthContext();

  const [serverUrl, setServerUrl] = useState('');
  const [showPreJoin, setShowPreJoin] = useState(() => getInitialShowPreJoin(searchParams));
  const [audioEnabled, setAudioEnabled] = useState(true);
  const [videoEnabled, setVideoEnabled] = useState(true);
  const [avReady, setAvReady] = useState(false);
  const [lessonCompleted, setLessonCompleted] = useState(false);
  const [effectiveLessonId, setEffectiveLessonId] = useState(null);
  const [boardId, setBoardId] = useState(null);
  const [boardLoading, setBoardLoading] = useState(false);
  const [showBoard, setShowBoard] = useState(false);
  const boardPollRef = useRef(null);

  // Load audio/video preferences from localStorage after mount
  useEffect(() => {
    const saved = getSavedAudioVideo();
    setAudioEnabled(saved.audio);
    setVideoEnabled(saved.video);
    setAvReady(true);
  }, []);

  // Determine effective lesson ID
  useEffect(() => {
    const id = lessonIdParam ? parseInt(lessonIdParam, 10) : null;
    if (id && !Number.isNaN(id)) {
      setEffectiveLessonId(id);
      try {
        sessionStorage.setItem('livekit_lesson_id', String(id));
      } catch { /* ignore */ }
    } else {
      try {
        const stored = sessionStorage.getItem('livekit_lesson_id');
        if (stored) setEffectiveLessonId(parseInt(stored, 10));
      } catch { /* ignore */ }
    }
  }, [lessonIdParam]);

  // Load server URL + check lesson status
  useEffect(() => {
    const load = async () => {
      if (lessonIdParam) {
        try {
          const l = await getLesson(lessonIdParam);
          if (l.status === 'completed') {
            const now = new Date();
            const end = l.completed_at ? new Date(l.completed_at) : new Date(l.end_time);
            if (now > new Date(end.getTime() + 10 * 60000)) setLessonCompleted(true);
          }
        } catch { /* ignore */ }
      }
      try {
        const config = await getLiveKitConfig();
        setServerUrl(config.server_url || 'ws://127.0.0.1:7880');
      } catch { /* ignore */ }
    };
    load();
  }, [lessonIdParam]);

  // Board: from token metadata or poll API
  useEffect(() => {
    const meta = getTokenMetadata(accessToken);
    if (meta.board_id) {
      setBoardId(meta.board_id);
      setBoardLoading(false);
      return undefined;
    }
    if (!effectiveLessonId) {
      setBoardLoading(false);
      return undefined;
    }
    let cancelled = false;
    const stopPoll = () => {
      if (boardPollRef.current) {
        clearInterval(boardPollRef.current);
        boardPollRef.current = null;
      }
    };
    setBoardLoading(true);
    getOrCreateLessonBoard(effectiveLessonId)
      .then((b) => {
        if (!cancelled) {
          setBoardId(b.board_id);
          stopPoll();
        }
      })
      .catch(() => {})
      .finally(() => {
        if (!cancelled) setBoardLoading(false);
      });
    boardPollRef.current = setInterval(() => {
      if (cancelled) return;
      getOrCreateLessonBoard(effectiveLessonId)
        .then((b) => {
          if (!cancelled) {
            setBoardId(b.board_id);
            stopPoll();
          }
        })
        .catch(() => {});
    }, 10_000);
    return () => {
      cancelled = true;
      stopPoll();
    };
  }, [accessToken, effectiveLessonId]);

  if (lessonCompleted) {
    return (
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', background: '#f5f5f5' }}>
        <div style={{ textAlign: 'center', padding: 24 }}>
          <p style={{ fontSize: 18, marginBottom: 16 }}>Урок завершён. Видеоконференция недоступна.</p>
          <button type="button" onClick={() => router.push('/dashboard')} style={{ padding: '12px 24px', borderRadius: 12, border: 'none', background: '#1976d2', color: '#fff', cursor: 'pointer' }}>
            На главную
          </button>
        </div>
      </div>
    );
  }

  if (!accessToken || !serverUrl) {
    return (
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh' }}>
        <p>Загрузка...</p>
      </div>
    );
  }

  if (showPreJoin) {
    return (
      <PreJoinScreen
        onJoin={(audio, video) => {
          try {
            sessionStorage.setItem(SS_PREJOIN_DONE, '1');
          } catch { /* ignore */ }
          setAudioEnabled(audio);
          setVideoEnabled(video);
          setShowPreJoin(false);
        }}
        onCancel={() => router.push('/dashboard')}
      />
    );
  }

  if (!avReady) {
    return (
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh' }}>
        <p>Загрузка...</p>
      </div>
    );
  }

  return (
    <>
      {boardId && (
        <div
          key="board-layer"
          style={{ position: 'fixed', inset: 0, zIndex: showBoard ? 9999 : 0, pointerEvents: showBoard ? 'auto' : 'none' }}
        >
          <WhiteboardIframe boardId={boardId} showingBoard={showBoard} />
        </div>
      )}
      <LiveKitRoom
        token={accessToken}
        serverUrl={serverUrl}
        connect
        audio={audioEnabled}
        video={videoEnabled}
        onDisconnected={() => router.push('/dashboard')}
        style={{ height: '100vh' }}
        data-lk-theme="default"
        options={{
          adaptiveStream: true,
          dynacast: true,
          videoCaptureDefaults: { resolution: PRESET_2K.resolution, frameRate: 30 },
          publishDefaults: {
            simulcast: true,
            videoEncoding: PRESET_2K.encoding,
            videoSimulcastLayers: [VideoPresets.h720, VideoPresets.h360],
            screenShareEncoding: { maxBitrate: 6_000_000, maxFramerate: 30 },
            screenShareSimulcastLayers: [VideoPresets.h720, VideoPresets.h360],
            degradationPreference: 'maintain-resolution',
          },
          audioCaptureDefaults: { noiseSuppression: true, echoCancellation: true },
        }}
      >
        <RoomContent
          lessonId={effectiveLessonId}
          boardId={boardId}
          boardLoading={boardLoading}
          showBoard={showBoard}
          setShowBoard={setShowBoard}
        />
        <RoomAudioRenderer />
        <ConnectionStateToast />
      </LiveKitRoom>
    </>
  );
}
