'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 'src/routes/hooks';
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 { paths } from 'src/routes/paths';
import { getLesson, completeLesson } from 'src/utils/dashboard-api';
import { buildExcalidrawSrc, getOrCreateLessonBoard } from 'src/utils/board-api';
import { getLiveKitConfig, participantConnected, terminateRoom } from 'src/utils/livekit-api';
import { createChat, normalizeChat } from 'src/utils/chat-api';

// Payload sent via LiveKit DataChannel to force-disconnect all participants
const TERMINATE_MSG = JSON.stringify({ type: 'room_terminate' });

import { Iconify } from 'src/components/iconify';
import { ChatWindow } from 'src/sections/chat/chat-window';
import { NavMobile } from 'src/layouts/dashboard/nav-mobile';
import { getNavData } from 'src/layouts/config-nav-dashboard';

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.7)', backdropFilter: 'blur(12px)', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 20 }}>
      <div style={{ background: 'rgba(255,255,255,0.06)', border: '1px solid rgba(255,255,255,0.12)', borderRadius: 20, padding: '32px 40px', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 20, maxWidth: 360, textAlign: 'center' }}>
        <div style={{ width: 56, height: 56, borderRadius: '50%', background: 'rgba(25,118,210,0.2)', border: '1px solid rgba(25,118,210,0.4)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <Iconify icon="solar:volume-loud-bold" width={28} style={{ color: '#60a5fa' }} />
        </div>
        <p style={{ color: '#fff', fontSize: 16, margin: 0, lineHeight: 1.5 }}>Чтобы слышать собеседника, разрешите воспроизведение звука</p>
        <button type="button" onClick={handleClick} style={{ padding: '12px 28px', fontSize: 14, fontWeight: 600, borderRadius: 12, border: 'none', background: '#1976d2', color: '#fff', cursor: 'pointer', letterSpacing: '0.02em' }}>
          Разрешить звук
        </button>
      </div>
    </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: 96, right: chatOpen ? CHAT_PANEL_WIDTH + 16 : 16, width: 220, height: 124, zIndex: 10000, borderRadius: 12, overflow: 'hidden', boxShadow: '0 8px 32px rgba(0,0,0,0.7), 0 0 0 1px rgba(255,255,255,0.1)', background: '#000' }}>
      <ParticipantTile trackRef={remoteRef} />
    </div>
  );
}

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

function WhiteboardIframe({ boardId, showingBoard, user }) {
  const iframeRef = useRef(null);

  const excalidrawConfigured = !!(
    process.env.NEXT_PUBLIC_EXCALIDRAW_URL ||
    process.env.NEXT_PUBLIC_EXCALIDRAW_PATH
  );

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

  if (!excalidrawConfigured) {
    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: 640 }, height: { ideal: 480 } }, 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);
  };

  const S = {
    page: { display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100vh', background: '#0d0d0d', overflow: 'hidden' },
    card: { background: 'rgba(255,255,255,0.05)', border: '1px solid rgba(255,255,255,0.10)', borderRadius: 22, width: '100%', maxWidth: 480, overflow: 'hidden', boxShadow: '0 24px 64px rgba(0,0,0,0.6)' },
    header: { padding: '24px 28px 20px', borderBottom: '1px solid rgba(255,255,255,0.08)' },
    title: { fontSize: 20, fontWeight: 700, color: '#fff', margin: 0 },
    sub: { fontSize: 13, color: 'rgba(255,255,255,0.5)', margin: '4px 0 0' },
    body: { padding: 24, display: 'flex', flexDirection: 'column', gap: 16 },
    preview: { background: '#111', borderRadius: 14, aspectRatio: '16/9', overflow: 'hidden', position: 'relative' },
    previewOff: { position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 10, color: 'rgba(255,255,255,0.35)' },
    toggleRow: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '12px 16px', background: 'rgba(255,255,255,0.04)', border: '1px solid rgba(255,255,255,0.07)', borderRadius: 12 },
    toggleLabel: { display: 'flex', alignItems: 'center', gap: 10, color: 'rgba(255,255,255,0.85)', fontSize: 14 },
    toggleBtn: (on) => ({ padding: '7px 18px', borderRadius: 9, border: 'none', background: on ? 'rgba(25,118,210,0.25)' : 'rgba(255,255,255,0.08)', color: on ? '#60a5fa' : 'rgba(255,255,255,0.5)', fontSize: 13, fontWeight: 600, cursor: 'pointer', transition: 'all 0.15s' }),
    actions: { display: 'flex', gap: 10 },
    cancelBtn: { flex: 1, padding: '13px', borderRadius: 12, border: '1px solid rgba(255,255,255,0.12)', background: 'transparent', color: 'rgba(255,255,255,0.6)', fontSize: 14, cursor: 'pointer' },
    joinBtn: { flex: 2, padding: '13px', borderRadius: 12, border: 'none', background: 'linear-gradient(135deg, #1976d2 0%, #1565c0 100%)', color: '#fff', fontSize: 14, fontWeight: 700, cursor: 'pointer', letterSpacing: '0.02em', boxShadow: '0 4px 16px rgba(25,118,210,0.35)' },
  };

  const devices = [
    { key: 'mic', label: 'Микрофон', icon: audioEnabled ? 'solar:microphone-bold' : 'solar:microphone-slash-bold', enabled: audioEnabled, toggle: () => setAudioEnabled((v) => !v) },
    { key: 'cam', label: 'Камера', icon: videoEnabled ? 'solar:camera-bold' : 'solar:camera-slash-bold', enabled: videoEnabled, toggle: () => setVideoEnabled((v) => !v) },
  ];

  return (
    <div style={S.page}>
      <div style={S.card}>
        <div style={S.header}>
          <p style={S.title}>Настройки перед входом</p>
          <p style={S.sub}>Проверьте камеру и микрофон</p>
        </div>
        <div style={S.body}>
          <div style={S.preview}>
            {videoEnabled
              ? <video ref={videoRef} autoPlay playsInline muted style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
              : (
                <div style={S.previewOff}>
                  <Iconify icon="solar:camera-slash-bold" width={40} />
                  <span style={{ fontSize: 13 }}>Камера выключена</span>
                </div>
              )}
          </div>

          <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
            {devices.map(({ key, label, icon, enabled, toggle }) => (
              <div key={key} style={S.toggleRow}>
                <span style={S.toggleLabel}>
                  <Iconify icon={icon} width={20} style={{ color: enabled ? '#60a5fa' : 'rgba(255,255,255,0.35)' }} />
                  {label}
                </span>
                <button type="button" onClick={toggle} style={S.toggleBtn(enabled)}>
                  {enabled ? 'Вкл' : 'Выкл'}
                </button>
              </div>
            ))}
          </div>

          <div style={S.actions}>
            <button type="button" onClick={onCancel} style={S.cancelBtn}>Отмена</button>
            <button type="button" onClick={handleJoin} style={S.joinBtn}>Войти в конференцию</button>
          </div>
        </div>
      </div>
    </div>
  );
}

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

// Panel width constant already defined at top
// ----------------------------------------------------------------------

function VideoCallChatPanel({ lesson, currentUser, onClose }) {
  const [chat, setChat] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    if (!lesson || !currentUser) return;
    const getOtherUserId = () => {
      if (currentUser.role === 'mentor') {
        const client = lesson.client;
        if (!client) return null;
        if (typeof client === 'object') return client.user?.id ?? client.id ?? null;
        return client;
      }
      const mentor = lesson.mentor;
      if (!mentor) return null;
      if (typeof mentor === 'object') return mentor.id ?? null;
      return mentor;
    };

    const otherId = getOtherUserId();
    if (!otherId) {
      setError('Не удалось определить собеседника');
      setLoading(false);
      return;
    }

    setLoading(true);
    createChat(otherId)
      .then((raw) => {
        const enriched = { ...raw };
        if (!enriched.other_participant) {
          // fallback: determine name from lesson data
          const other = currentUser.role === 'mentor' ? lesson.client : lesson.mentor;
          if (other && typeof other === 'object') {
            const u = other.user || other;
            enriched.other_participant = {
              id: otherId,
              first_name: u.first_name,
              last_name: u.last_name,
              avatar_url: u.avatar_url || u.avatar || null,
            };
          }
        }
        setChat(normalizeChat(enriched));
      })
      .catch((e) => setError(e?.response?.data?.detail || e?.message || 'Ошибка загрузки чата'))
      .finally(() => setLoading(false));
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [lesson?.id, currentUser?.id]);

  return (
    <div style={{ position: 'fixed', top: 0, right: 0, width: CHAT_PANEL_WIDTH, height: '100vh', background: '#0f0f0f', borderLeft: '1px solid rgba(255,255,255,0.08)', display: 'flex', flexDirection: 'column', zIndex: 10002, boxShadow: '-8px 0 40px rgba(0,0,0,0.5)' }}>
      {/* Header */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '14px 16px', borderBottom: '1px solid rgba(255,255,255,0.08)', flexShrink: 0 }}>
        <div style={{ width: 36, height: 36, borderRadius: '50%', background: 'linear-gradient(135deg, #1976d2, #7c4dff)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
          <Iconify icon="solar:chat-round-bold" width={18} style={{ color: '#fff' }} />
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ color: '#fff', fontWeight: 600, fontSize: 14, lineHeight: 1.3 }}>Чат</div>
        </div>
        <button type="button" onClick={onClose} style={{ width: 32, height: 32, borderRadius: 8, border: 'none', background: 'rgba(255,255,255,0.06)', color: 'rgba(255,255,255,0.6)', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
          <Iconify icon="solar:close-circle-bold" width={18} />
        </button>
      </div>

      {loading && (
        <div style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 12, color: 'rgba(255,255,255,0.35)' }}>
          <Iconify icon="svg-spinners:ring-resize" width={28} style={{ color: '#1976d2' }} />
          <span style={{ fontSize: 13 }}>Загрузка чата…</span>
        </div>
      )}
      {error && (
        <div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 20, textAlign: 'center', color: '#fc8181', fontSize: 13 }}>
          {error}
        </div>
      )}
      {!loading && !error && (
        <ChatWindow chat={chat} currentUserId={currentUser?.id ?? null} hideHeader />
      )}
    </div>
  );
}

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

function RoomContent({ lessonId, lesson, boardId, boardLoading, showBoard, setShowBoard, postDisconnectRef }) {
  const room = useRoomContext();
  const router = useRouter();
  const { user } = useAuthContext();
  const [showPlatformChat, setShowPlatformChat] = useState(false);
  const [showExitMenu, setShowExitMenu] = useState(false);
  const [showNavMenu, setShowNavMenu] = useState(false);
  const [terminatingAll, setTerminatingAll] = useState(false);
  const [exitBtnRect, setExitBtnRect] = useState(null);
  const exitBtnRef = useRef(null);
  const isMentor = user?.role === 'mentor';

  const handleToggleExitMenu = () => {
    if (!showExitMenu && exitBtnRef.current) {
      setExitBtnRect(exitBtnRef.current.getBoundingClientRect());
    }
    setShowExitMenu((v) => !v);
  };

  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', (ev) => window.dispatchEvent(new CustomEvent('livekit-exit-click', { detail: { target: ev.currentTarget } })));
        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(() => {
    // Control bar button click: capture its rect for popup positioning
    const handler = (e) => {
      const btn = e?.detail?.target ?? document.querySelector('.lk-custom-exit-button');
      if (btn) setExitBtnRect(btn.getBoundingClientRect());
      setShowExitMenu(true);
    };
    window.addEventListener('livekit-exit-click', handler);
    return () => window.removeEventListener('livekit-exit-click', handler);
  }, []);

  const handleJustExit = () => {
    setShowExitMenu(false);
    room.disconnect();
  };

  const handleTerminateForAll = async () => {
    setShowExitMenu(false);
    setTerminatingAll(true);
    if (lessonId != null) {
      try { sessionStorage.setItem('complete_lesson_id', String(lessonId)); } catch { /* ignore */ }
      if (postDisconnectRef) postDisconnectRef.current = paths.dashboard.calendar;

      // 1. Broadcast terminate signal via LiveKit DataChannel so clients
      //    disconnect immediately (fallback if backend call is slow/fails).
      try {
        await room.localParticipant.publishData(
          new TextEncoder().encode(TERMINATE_MSG),
          { reliable: true }
        );
      } catch { /* ignore */ }

      // 2. Backend: terminate LiveKit room + mark lesson as completed.
      try { await terminateRoom(lessonId); } catch { /* ignore */ }

      // 3. Ensure lesson status is "completed" on backend even if
      //    terminateRoom doesn't handle it.
      try { await completeLesson(String(lessonId), '', undefined, undefined, undefined, false, undefined); } catch { /* ignore */ }
    }
    room.disconnect();
  };

  // Listen for terminate broadcast from mentor (runs on client side).
  useEffect(() => {
    if (isMentor) return undefined;
    const onData = (payload) => {
      try {
        const msg = JSON.parse(new TextDecoder().decode(payload));
        if (msg?.type === 'room_terminate') {
          room.disconnect();
        }
      } catch { /* ignore */ }
    };
    room.on(RoomEvent.DataReceived, onData);
    return () => { room.off(RoomEvent.DataReceived, onData); };
  }, [room, isMentor]);

  // 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 sidebarRight = showPlatformChat ? CHAT_PANEL_WIDTH + 12 : 12;

  const SideBtn = ({ active, disabled: dis, title, icon, onClick: handleClick }) => (
    <button
      type="button"
      onClick={handleClick}
      disabled={dis}
      title={title}
      style={{
        width: 44,
        height: 44,
        borderRadius: 12,
        border: active ? '1px solid rgba(25,118,210,0.5)' : '1px solid rgba(255,255,255,0.08)',
        background: active ? 'rgba(25,118,210,0.25)' : 'rgba(255,255,255,0.06)',
        color: active ? '#60a5fa' : dis ? 'rgba(255,255,255,0.2)' : 'rgba(255,255,255,0.7)',
        cursor: dis ? 'not-allowed' : 'pointer',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        transition: 'all 0.15s ease',
        flexShrink: 0,
      }}
    >
      <Iconify icon={icon} width={20} />
    </button>
  );

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

      {typeof document !== 'undefined' &&
        createPortal(
          <>
            {showBoard && <RemoteParticipantPiP chatOpen={showPlatformChat} />}

            {/* Board burger button */}
            {showBoard && (
              <button
                type="button"
                onClick={() => setShowNavMenu((v) => !v)}
                title="Меню"
                style={{ position: 'fixed', left: 12, bottom: 96, width: 44, height: 44, borderRadius: 12, border: '1px solid rgba(255,255,255,0.10)', background: 'rgba(15,15,15,0.85)', backdropFilter: 'blur(12px)', color: 'rgba(255,255,255,0.7)', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 10002 }}
              >
                <Iconify icon="solar:hamburger-menu-bold" width={20} />
              </button>
            )}

            {/* Nav menu — existing NavMobile, all links open in new tab */}
            <NavMobile
              open={showNavMenu}
              onClose={() => setShowNavMenu(false)}
              data={getNavData(user?.role).map((section) => ({
                ...section,
                items: section.items.map((item) => ({ ...item, externalLink: true })),
              }))}
              sx={{ bgcolor: 'grey.900', width: 300 }}
            />

            {/* Right sidebar */}
            <div style={{ position: 'fixed', right: sidebarRight, top: '50%', transform: 'translateY(-50%)', display: 'flex', flexDirection: 'column', gap: 6, padding: 6, background: 'rgba(10,10,10,0.80)', backdropFilter: 'blur(16px)', border: '1px solid rgba(255,255,255,0.08)', borderRadius: 16, zIndex: 10001, transition: 'right 0.25s ease' }}>
              <SideBtn active={!showBoard} disabled={false} title="Видеоконференция" icon="solar:videocamera-bold" onClick={() => setShowBoard(false)} />
              <SideBtn
                active={showBoard}
                disabled={!boardId || boardLoading}
                title={boardLoading ? 'Загрузка доски…' : !boardId ? 'Доска недоступна' : 'Доска'}
                icon={boardLoading ? 'svg-spinners:ring-resize' : 'solar:pen-new-square-bold'}
                onClick={() => boardId && !boardLoading && setShowBoard(true)}
              />
              {lessonId != null && (
                <SideBtn active={showPlatformChat} disabled={false} title="Чат" icon="solar:chat-round-bold" onClick={() => setShowPlatformChat((v) => !v)} />
              )}
              {/* Divider */}
              <div style={{ height: 1, background: 'rgba(255,255,255,0.10)', margin: '2px 0' }} />
              {/* Exit button */}
              <button
                ref={exitBtnRef}
                type="button"
                onClick={handleToggleExitMenu}
                title="Выйти"
                style={{ width: 44, height: 44, borderRadius: 12, border: `1px solid ${showExitMenu ? 'rgba(239,68,68,0.6)' : 'rgba(239,68,68,0.35)'}`, background: showExitMenu ? 'rgba(239,68,68,0.22)' : 'rgba(239,68,68,0.12)', color: '#f87171', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', transition: 'all 0.15s ease', flexShrink: 0 }}
              >
                <Iconify icon={showExitMenu ? 'solar:close-bold' : 'solar:exit-bold'} width={20} />
              </button>
            </div>

            {/* Exit menu popup — anchored to the exit button rect */}
            {showExitMenu && exitBtnRect && (
              <>
                {/* Backdrop */}
                <div
                  style={{ position: 'fixed', inset: 0, zIndex: 10010 }}
                  onClick={() => setShowExitMenu(false)}
                />
                {/* Popup: right edge aligned with exit button right edge, bottom edge at exit button top - 8px */}
                <div style={{
                  position: 'fixed',
                  right: window.innerWidth - exitBtnRect.right,
                  bottom: window.innerHeight - exitBtnRect.top + 8,
                  zIndex: 10011,
                  background: 'rgba(18,18,18,0.97)',
                  border: '1px solid rgba(255,255,255,0.12)',
                  borderRadius: 14,
                  padding: 8,
                  backdropFilter: 'blur(20px)',
                  display: 'flex',
                  flexDirection: 'column',
                  gap: 6,
                  minWidth: 240,
                  boxShadow: '0 8px 32px rgba(0,0,0,0.6)',
                }}>
                  <button
                    type="button"
                    onClick={handleJustExit}
                    style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '11px 14px', borderRadius: 10, border: 'none', background: 'rgba(255,255,255,0.06)', color: 'rgba(255,255,255,0.85)', fontSize: 14, cursor: 'pointer', textAlign: 'left', whiteSpace: 'nowrap' }}
                  >
                    <Iconify icon="solar:exit-bold" width={18} style={{ color: '#94a3b8', flexShrink: 0 }} />
                    Выйти
                  </button>
                  {isMentor && (
                    <button
                      type="button"
                      onClick={handleTerminateForAll}
                      disabled={terminatingAll}
                      style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '11px 14px', borderRadius: 10, border: 'none', background: 'rgba(239,68,68,0.12)', color: terminatingAll ? 'rgba(248,113,113,0.5)' : '#f87171', fontSize: 14, cursor: terminatingAll ? 'not-allowed' : 'pointer', textAlign: 'left', whiteSpace: 'nowrap' }}
                    >
                      <Iconify
                        icon={terminatingAll ? 'svg-spinners:ring-resize' : 'solar:close-circle-bold'}
                        width={18}
                        style={{ color: terminatingAll ? 'rgba(248,113,113,0.5)' : '#f87171', flexShrink: 0 }}
                      />
                      {terminatingAll ? 'Завершение…' : 'Выйти и завершить для всех'}
                    </button>
                  )}
                </div>
              </>
            )}

            {showPlatformChat && lesson && (
              <VideoCallChatPanel
                lesson={lesson}
                currentUser={user}
                onClose={() => setShowPlatformChat(false)}
              />
            )}
          </>,
          document.body
        )}
    </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 [lesson, setLesson] = useState(null);
  const [boardId, setBoardId] = useState(null);
  const [boardLoading, setBoardLoading] = useState(false);
  const [showBoard, setShowBoard] = useState(false);
  const boardPollRef = useRef(null);
  const postDisconnectRef = useRef('/dashboard');

  // Lock scroll while on the video-call page, restore on unmount
  useEffect(() => {
    const prev = document.documentElement.style.overflow;
    document.documentElement.style.overflow = 'hidden';
    document.body.style.overflow = 'hidden';
    return () => {
      document.documentElement.style.overflow = prev;
      document.body.style.overflow = '';
    };
  }, []);

  // 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);
          setLesson(l);
          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} user={user} />
        </div>
      )}
      <LiveKitRoom
        token={accessToken}
        serverUrl={serverUrl}
        connect
        audio={audioEnabled}
        video={videoEnabled}
        onDisconnected={() => router.push(postDisconnectRef.current)}
        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}
          lesson={lesson}
          boardId={boardId}
          boardLoading={boardLoading}
          showBoard={showBoard}
          setShowBoard={setShowBoard}
          postDisconnectRef={postDisconnectRef}
        />
        <RoomAudioRenderer />
        <ConnectionStateToast />
      </LiveKitRoom>
    </>
  );
}
