import {
  Hand,
  Image,
  LogOut,
  Maximize,
  MessageSquare,
  Mic,
  MicOff,
  Minimize,
  PictureInPicture2,
  ScreenShare,
  ScreenShareOff,
  Settings,
  Video,
  VideoOff,
} from 'lucide-react'
import { Track } from 'livekit-client'
import { DisconnectButton, useLocalParticipant, useTrackToggle } from '@livekit/components-react'
import { useToast } from '@/components/ui/ToastProvider'
import { useIsCompactViewport } from '@/hooks/useIsCompactViewport'
import type { HandQueueEntry } from '@/hooks/useChat'
import { StageViewMenu, type StageViewProps } from '@/components/room/StageViewOptions'
import { HandQueueMenu } from '@/components/room/HandQueueMenu'
import { SCREEN_SHARE_CAPTURE_OPTIONS } from '@/lib/screenShareOptions'

interface RoomToolbarProps extends StageViewProps {
  /** Показывать ли кнопку чата — `JoinOut.chat_enabled` И чат не помечен недоступным (close-код 4404). */
  chatVisible: boolean
  chatOpen: boolean
  /** Число непрочитанных сообщений, накопленных со времени последнего открытия панели. */
  chatUnreadCount: number
  onToggleChat: () => void
  /** Открыть диалог настроек устройств. */
  onToggleSettings: () => void
  /** `document.fullscreenEnabled` — false скрывает кнопку. */
  fullscreenSupported: boolean
  fullscreenActive: boolean
  onToggleFullscreen: () => void
  /** Доступен ли мини-плеер хоть в каком-то виде (Document PiP либо video-фолбэк) — false в Firefox скрывает кнопку. */
  pipSupported: boolean
  pipActive: boolean
  onTogglePiP: () => void
  /** `JoinOut.hand_queue_enabled` — при `false` кнопка «Рука» и очередь не рендерятся вовсе. */
  handQueueEnabled: boolean
  /**
   * Показывать ли кнопку «Фон». Уже учитывает ВСЁ сразу: включён ли модуль в
   * админке, десктопное ли это устройство и умеет ли браузер сегментацию —
   * см. `RoomPage`. При `false` кнопки нет вовсе (а не задизейбленной): на
   * телефоне фичи не существует, и мёртвая кнопка там только мешает.
   */
  backgroundVisible: boolean
  backgroundOpen: boolean
  onToggleBackground: () => void
  /**
   * Очередь поднятых рук целиком (задача B1, `useChat().handQueue`) — сама
   * решает, поднята ли СВОЯ рука (сравнивая с `localParticipant.identity`
   * через `useLocalParticipant`), и показывает бейдж общего счётчика.
   */
  handQueue: HandQueueEntry[]
  onRaiseHand: () => void
  onLowerHand: () => void
  /** Опустить ЧУЖУЮ руку по identity — только организатору (панель очереди, `HandQueueMenu`). */
  onLowerHandById: (identity: string) => void
  /** Тулбар в оверлее полноэкранного режима — см. докстринг `RoomTopbar.overlayVisible`, тот же механизм. */
  overlayVisible?: boolean
  /**
   * Пользователь нажал «Выйти» — вызывается ПЕРЕД тем, как `DisconnectButton`
   * отключит комнату (обработчики в `mergeProps` вызываются цепочкой). Нужен
   * `RoomPage`, чтобы отличить намеренный выход от разрыва: причина
   * `CLIENT_INITIATED` приходит и от кнопки, и от livekit-client при заморозке
   * вкладки — см. докстринг `handleDisconnected`.
   */
  onLeave?: () => void
}

/**
 * Нижний тулбар комнаты: микрофон/камера/демонстрация экрана/рука/очередь
 * рук/вид сцены/настройки устройств/полноэкранный режим/мини-плеер/чат/выход —
 * собственные кнопки на хуках LiveKit (useTrackToggle/DisconnectButton) и
 * панели чата, стилизованные по design/mockups/room.html.
 *
 * Кнопка «Вид» (режимы показа и скрытие остальных) рендерится ТОЛЬКО на
 * широком экране — условным рендерингом, а не скрытием через CSS: демонстрация
 * и мини-плеер скрыты на узком экране через CSS (см. `styles/room.css`), а те
 * же настройки показа сцены доступны секцией «Вид» в шторке настроек
 * (`DeviceSettingsDialog`). «Рука» — сознательное исключение из этой
 * экономии: поднять руку посреди разговора — действие со временем жизни в
 * секунды, прятать его в шторку настроек означало бы делать его практически
 * недоступным с телефона. «Очередь» видна ЛЮБОМУ участнику (сессия
 * «28-hand-queue-for-all»: раньше только организатору), по той же причине
 * оставлена в тулбаре, а не в шторке: любому участнику с телефона тоже нужно
 * видеть очередь сразу. Обе кнопки целиком гасятся `handQueueEnabled`
 * (`JoinOut.hand_queue_enabled`, отключаемый модуль в админке).
 * Полноэкранный режим на мобильном ОСТАЁТСЯ в тулбаре (не спрятан в шторку,
 * как демонстрация/мини-плеер) — по решению оператора вход в него должен
 * быть по аналогии с десктопом; если из-за этого кнопки не помещаются в один
 * ряд, `mobileButtonCount`/`.tb-wrap-grid` ниже раскладывают их равномерной
 * сеткой, а не как получится через `flex-wrap`.
 */
export function RoomToolbar({
  chatVisible,
  chatOpen,
  chatUnreadCount,
  onToggleChat,
  onToggleSettings,
  fullscreenSupported,
  fullscreenActive,
  onToggleFullscreen,
  pipSupported,
  pipActive,
  onTogglePiP,
  handQueueEnabled,
  backgroundVisible,
  backgroundOpen,
  onToggleBackground,
  handQueue,
  onRaiseHand,
  onLowerHand,
  onLowerHandById,
  layoutMode,
  onLayoutModeChange,
  hideOthers,
  onHideOthersChange,
  overlayVisible,
  onLeave,
}: RoomToolbarProps) {
  const toast = useToast()
  const isCompact = useIsCompactViewport()
  const { localParticipant } = useLocalParticipant()
  const handRaised = handQueue.some((entry) => entry.identity === localParticipant.identity)

  // Сколько кнопок реально видно на мобильном (демонстрация/мини-окно там
  // скрыты через CSS всегда, «Вид» не рендерится вовсе — см. докстринг) —
  // считаем в JS, а не через CSS-селекторы вида `:nth-child`: у «Очереди»
  // в DOM есть своя обёртка `.tb-menu-wrap`, из-за которой позиция остальных
  // кнопок «плывёт», и подсчёт по структуре DOM был бы хрупким. От порога
  // зависит `.tb-wrap-grid` в room.css — ниже он переключает перенос на
  // 2 строки с «как поместится» (flex-wrap) на равномерную сетку 4 колонки
  // (7 → 4+3, 8 → 4+4). «Рука»/«Очередь» — обе теперь видны любому участнику
  // (сессия «28-hand-queue-for-all»), их наличие зависит только от
  // `handQueueEnabled`, не от роли.
  const mobileButtonCount =
    2 /* микрофон, камера */ +
    (handQueueEnabled ? 2 : 0) /* рука, очередь */ +
    1 /* настройки */ +
    // На телефоне всегда 0 (фича десктопная), но десктопное окно бывает и уже
    // 600px — тогда кнопка «Фон» реально есть и должна попасть в подсчёт.
    (backgroundVisible ? 1 : 0) +
    (fullscreenSupported ? 1 : 0) +
    (chatVisible ? 1 : 0) +
    1 /* выйти */
  const mic = useTrackToggle({ source: Track.Source.Microphone })
  const camera = useTrackToggle({ source: Track.Source.Camera })
  const screenShare = useTrackToggle({
    source: Track.Source.ScreenShare,
    captureOptions: SCREEN_SHARE_CAPTURE_OPTIONS,
    // Отмена браузерного диалога выбора экрана/окна (пользователь нажал
    // «Отмена») приходит сюда как NotAllowedError — молча игнорируем, это не
    // ошибка приложения. Прочие сбои (например, `NotReadableError` при
    // занятом источнике) показываем тостом.
    onDeviceError: (error) => {
      if (error.name === 'NotAllowedError') return
      toast.show('Не удалось начать демонстрацию экрана', 'error')
    },
  })

  return (
    <footer
      className={`room-toolbar${overlayVisible ? ' is-visible' : ''}${mobileButtonCount >= 7 ? ' tb-wrap-grid' : ''}`}
    >
      <button
        type="button"
        {...mic.buttonProps}
        className={`tb-btn${mic.enabled ? '' : ' is-off'}`}
        aria-label={mic.enabled ? 'Выключить микрофон' : 'Включить микрофон'}
      >
        <span className="icon-shell">
          {mic.enabled ? (
            <Mic className="lucide" aria-hidden="true" />
          ) : (
            <MicOff className="lucide" aria-hidden="true" />
          )}
        </span>
        <span className="label">Микрофон</span>
      </button>

      <button
        type="button"
        {...camera.buttonProps}
        className={`tb-btn${camera.enabled ? '' : ' is-off'}`}
        aria-label={camera.enabled ? 'Выключить камеру' : 'Включить камеру'}
      >
        <span className="icon-shell">
          {camera.enabled ? (
            <Video className="lucide" aria-hidden="true" />
          ) : (
            <VideoOff className="lucide" aria-hidden="true" />
          )}
        </span>
        <span className="label">Камера</span>
      </button>

      <button
        type="button"
        {...screenShare.buttonProps}
        className={`tb-btn tb-btn--screenshare${screenShare.enabled ? ' is-sharing' : ''}`}
        aria-label={screenShare.enabled ? 'Остановить демонстрацию экрана' : 'Демонстрировать экран'}
      >
        <span className="icon-shell">
          {screenShare.enabled ? (
            <ScreenShareOff className="lucide" aria-hidden="true" />
          ) : (
            <ScreenShare className="lucide" aria-hidden="true" />
          )}
        </span>
        <span className="label">Демонстрация</span>
      </button>

      {handQueueEnabled && (
        <button
          type="button"
          className={`tb-btn${handRaised ? ' is-hand-raised' : ''}`}
          aria-pressed={handRaised}
          aria-label={handRaised ? 'Опустить руку' : 'Поднять руку'}
          onClick={() => (handRaised ? onLowerHand() : onRaiseHand())}
        >
          <span className="icon-shell">
            <Hand className="lucide" aria-hidden="true" />
            {handQueue.length > 0 && (
              <span className="badge-count">{handQueue.length > 9 ? '9+' : handQueue.length}</span>
            )}
          </span>
          <span className="label">Рука</span>
        </button>
      )}

      {handQueueEnabled && <HandQueueMenu queue={handQueue} onLower={onLowerHandById} />}

      {!isCompact && (
        <StageViewMenu
          layoutMode={layoutMode}
          onLayoutModeChange={onLayoutModeChange}
          hideOthers={hideOthers}
          onHideOthersChange={onHideOthersChange}
        />
      )}

      <button
        type="button"
        className="tb-btn"
        aria-label="Настройки устройств"
        onClick={onToggleSettings}
      >
        <span className="icon-shell">
          <Settings className="lucide" aria-hidden="true" />
        </span>
        {/* На мобильном подпись шире по смыслу («Настройки»): там же в шторке
            секция «Вид», а отдельной кнопки под неё в тулбаре нет. На десктопе
            панель — только настройки устройств, подпись это отражает. */}
        <span className="label">{isCompact ? 'Настройки' : 'Устройства'}</span>
      </button>

      {/* Только десктоп — на мобильном `backgroundVisible` всегда false,
          поэтому кнопка не участвует и в `mobileButtonCount` выше. */}
      {backgroundVisible && (
        <button
          type="button"
          className={`tb-btn tb-btn--background${backgroundOpen ? ' is-panel-open' : ''}`}
          aria-label={backgroundOpen ? 'Закрыть выбор фона' : 'Выбрать фон'}
          aria-pressed={backgroundOpen}
          onClick={onToggleBackground}
        >
          <span className="icon-shell">
            <Image className="lucide" aria-hidden="true" />
          </span>
          <span className="label">Фон</span>
        </button>
      )}

      {fullscreenSupported && (
        <button
          type="button"
          className={`tb-btn tb-btn--fullscreen${fullscreenActive ? ' is-panel-open' : ''}`}
          aria-label={fullscreenActive ? 'Выйти из полноэкранного режима' : 'Развернуть на весь экран'}
          aria-pressed={fullscreenActive}
          onClick={onToggleFullscreen}
        >
          <span className="icon-shell">
            {fullscreenActive ? (
              <Minimize className="lucide" aria-hidden="true" />
            ) : (
              <Maximize className="lucide" aria-hidden="true" />
            )}
          </span>
          <span className="label">Экран</span>
        </button>
      )}

      {pipSupported && (
        <button
          type="button"
          className={`tb-btn tb-btn--pip${pipActive ? ' is-panel-open' : ''}`}
          aria-label={pipActive ? 'Свернуть мини-окно' : 'Открыть мини-окно'}
          aria-pressed={pipActive}
          onClick={onTogglePiP}
        >
          <span className="icon-shell">
            <PictureInPicture2 className="lucide" aria-hidden="true" />
          </span>
          {/* На узком экране («Мини-окно» иначе переносится на 2 строки и
              кнопка становится выше соседних, см. .label-full/.label-short
              в room.css) — только «Мини». Текст, не структура: aria-label
              выше уже несёт полный смысл независимо от видимой подписи. */}
          <span className="label">
            <span className="label-full">Мини-окно</span>
            <span className="label-short">Мини</span>
          </span>
        </button>
      )}

      {chatVisible && (
        <button
          type="button"
          className={`tb-btn${chatOpen ? ' is-panel-open' : ''}`}
          aria-label={chatOpen ? 'Свернуть чат' : 'Открыть чат'}
          aria-pressed={chatOpen}
          onClick={onToggleChat}
        >
          <span className="icon-shell">
            <MessageSquare className="lucide" aria-hidden="true" />
            {chatUnreadCount > 0 && (
              <span className="badge-count">{chatUnreadCount > 9 ? '9+' : chatUnreadCount}</span>
            )}
          </span>
          <span className="label">Чат</span>
        </button>
      )}

      <DisconnectButton className="tb-btn danger" aria-label="Выйти из конференции" onClick={onLeave}>
        <span className="icon-shell">
          <LogOut className="lucide" aria-hidden="true" />
        </span>
        <span className="label">Выйти</span>
      </DisconnectButton>
    </footer>
  )
}
