import UserCamera from "./ui/UserCamera";
import UserDevicesControls from "./ui/UserDevicesControls";
import DraggableContainer from "./DraggableContainer";
import { useWebRTC } from "../hooks/useWebRTC";
import clsx from "clsx";
import { useEffect, useRef, useState } from "react";
import type { Session } from "../types/Session";
import { getGuestId } from "../lib/guestId";
import { useMe } from "../hooks/useAuth";

// for test cameras grid
const LOCAL_CAMERAS_COUNT = 1;

interface SessionUsersPanelProps {
  roomId: string;
  autoJoin?: boolean;
  mode?: "full" | "mini";
  session?: Session;
}

function SessionUsersPanel({
  roomId,
  autoJoin = false,
  mode = "full",
  session,
}: SessionUsersPanelProps) {
  const {
    localStream,
    participants,
    isAudioMuted: isLocalAudioMuted,
    isVideoMuted: isLocalVideoMuted,
    toggleAudio,
    toggleVideo,
    updateSpeakingState,
    muteParticipant,
    disableParticipantVideo,
    grantControl,
    revokeControl,
    hasControl: localHasControl,
    currentUserId,
  } = useWebRTC(roomId, autoJoin);

  const hasLocalStream = localStream !== null;
  const { data: user } = useMe();

  // Определяем, является ли локальный пользователь организатором сессии
  const isLocalUserOrganizer = session
    ? !!(session.userId && user?.id === session.userId) ||
      !!(session.guestId && getGuestId() === session.guestId)
    : false;

  // Функция для определения, является ли конкретный участник организатором
  const isParticipantOrganizer = (participantId: string) => {
    if (!session) return false;
    return (
      (session.userId && participantId === session.userId) ||
      (session.guestId && participantId === session.guestId)
    );
  };

  // Логируем изменения hasLocalStream для отладки
  useEffect(() => {
    console.log(
      `[SessionUsersPanel] hasLocalStream changed to: ${hasLocalStream}`
    );
  }, [hasLocalStream]);

  // State для хранения состояния speaking
  const [localSpeaking, setLocalSpeaking] = useState<boolean>(false);
  const lastSentSpeakingRef = useRef<boolean>(false);
  const speakingStateTimeoutRef = useRef<NodeJS.Timeout | null>(null);

  // State для отслеживания размеров и ориентации экрана
  const [windowDimensions, setWindowDimensions] = useState({
    width: window.innerWidth,
    height: window.innerHeight,
  });

  // Callback для получения изменений состояния speaking от UserCamera
  const handleSpeakingChange = (isSpeaking: boolean) => {
    setLocalSpeaking(isSpeaking);
  };

  // useEffect для отслеживания изменения ориентации и размеров экрана
  useEffect(() => {
    const handleResize = () => {
      setWindowDimensions({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    };

    const handleOrientationChange = () => {
      // Небольшая задержка для корректного получения новых размеров после поворота
      setTimeout(() => {
        setWindowDimensions({
          width: window.innerWidth,
          height: window.innerHeight,
        });
      }, 100);
    };

    // Слушаем событие resize (срабатывает при изменении размера окна)
    window.addEventListener("resize", handleResize);

    // Слушаем событие orientationchange (срабатывает при повороте устройства)
    window.addEventListener("orientationchange", handleOrientationChange);

    // Также слушаем изменения в screen.orientation API (современный способ)
    if (screen.orientation) {
      screen.orientation.addEventListener("change", handleOrientationChange);
    }

    return () => {
      window.removeEventListener("resize", handleResize);
      window.removeEventListener("orientationchange", handleOrientationChange);
      if (screen.orientation) {
        screen.orientation.removeEventListener(
          "change",
          handleOrientationChange
        );
      }
    };
  }, []);

  // useEffect для throttle и отправки состояния speaking через socket
  useEffect(() => {
    // Отправляем только если состояние действительно изменилось
    if (lastSentSpeakingRef.current === localSpeaking) {
      return;
    }

    // Очищаем предыдущий таймер
    if (speakingStateTimeoutRef.current) {
      clearTimeout(speakingStateTimeoutRef.current);
    }

    // Отправляем состояние с задержкой (debounce 300ms)
    speakingStateTimeoutRef.current = setTimeout(() => {
      lastSentSpeakingRef.current = localSpeaking;
      updateSpeakingState?.(localSpeaking);
      speakingStateTimeoutRef.current = null;
    }, 300);

    return () => {
      if (speakingStateTimeoutRef.current) {
        clearTimeout(speakingStateTimeoutRef.current);
      }
    };
  }, [localSpeaking, updateSpeakingState]);

  // Вычисляем количество камер для grid
  const activeCamerasCount =
    (localStream ? LOCAL_CAMERAS_COUNT : 0) +
    participants.filter(
      (p) => p.stream != null && p.stream.getTracks().length > 0
    ).length;

  // Определяем количество колонок в зависимости от количества камер
  const getDesktopGridColumns = (count: number): number => {
    if (count <= 2) return 1;
    if (count <= 4) return 2;
    if (count <= 9) return 3;
    return 4;
  };

  const getMobilePortraitGridColumns = (count: number): number => {
    if (count <= 3) return 1;
    if (count <= 12) return 2;
    return 3;
  };

  const getMobileLandscapeGridColumns = (count: number): number => {
    if (count <= 3) return count;
    if (count <= 6) return 3;
    return 4;
  };

  const gridColumns =
    windowDimensions.width >= 1440
      ? getDesktopGridColumns(activeCamerasCount)
      : windowDimensions.height / windowDimensions.width < 1
      ? getMobileLandscapeGridColumns(activeCamerasCount)
      : getMobilePortraitGridColumns(activeCamerasCount);

  return (
    <DraggableContainer
      enableSnapping={mode === "mini"}
      enabled={mode === "mini"}
      autoAlign={true}
      initialCorner={
        windowDimensions.width >= 640 ? "bottom-right" : "top-right"
      }
      padding="1.111vw"
      className={clsx(
        "z-[100] 2xl:gap-[0.556vw] gap-2",
        mode === "mini"
          ? "flex"
          : `2xl:p-[2.778vw_5vw_5vw] p-[12px_12px_72px] w-full 2xl:h-dvh grid relative 2xl:bg-black auto-rows-fr`,
        gridColumns === 1
          ? "grid-cols-1"
          : gridColumns === 2
          ? "grid-cols-2"
          : gridColumns === 3
          ? "grid-cols-3"
          : "grid-cols-4"
      )}
    >
      {mode === "full" && <div className="fixed bg-black inset-0 2xl:hidden" />}
      {localStream &&
        Array.from({ length: LOCAL_CAMERAS_COUNT }).map((_, index) => (
          <UserCamera
            key={index}
            mode={mode}
            name="Вы"
            isMuted={isLocalAudioMuted}
            isVideoOff={isLocalVideoMuted}
            hasControl={localHasControl}
            isAdmin={isLocalUserOrganizer}
            isLocal={true}
            mediaStream={localStream}
            onSpeakingChange={handleSpeakingChange}
            isLocalUserOrganizer={isLocalUserOrganizer}
            participantId={currentUserId}
            onGrantControl={grantControl}
            onRevokeControl={revokeControl}
            className={clsx(
              mode === "full" &&
                (activeCamerasCount <= 2
                  ? "m-auto"
                  : "min-w-full w-full min-h-full")
            )}
          />
        ))}

      {/* Камеры удаленных участников - показываем только если есть поток с активными треками */}
      {participants
        .filter(
          (participant) =>
            participant.stream != null &&
            participant.stream.getTracks().length > 0
        )
        .map((participant) => (
          <UserCamera
            className={clsx(
              mode === "full" &&
                (activeCamerasCount <= 2
                  ? "m-auto"
                  : "min-w-full w-full min-h-full")
            )}
            key={participant.id}
            mode={mode}
            name={participant.name}
            isMuted={participant.isMuted || false}
            isVideoOff={participant.isVideoOff || false}
            isSpeaking={participant.isSpeaking}
            hasControl={participant.hasControl || false}
            isAdmin={isParticipantOrganizer(participant.id) || undefined}
            mediaStream={participant.stream}
            hasLocalMediaPermission={hasLocalStream}
            isLocalUserOrganizer={isLocalUserOrganizer}
            participantId={participant.id}
            onMuteParticipant={muteParticipant}
            onDisableParticipantVideo={disableParticipantVideo}
            onGrantControl={grantControl}
            onRevokeControl={revokeControl}
          />
        ))}

      <UserDevicesControls
        mode={mode}
        toggleAudio={toggleAudio}
        toggleVideo={toggleVideo}
        isAudioMuted={isLocalAudioMuted}
        isVideoMuted={isLocalVideoMuted}
        hasLocalStream={hasLocalStream}
        hasControl={localHasControl}
        onToggleControl={() => {
          // Организатор всегда может вернуть управление себе
          if (isLocalUserOrganizer) {
            revokeControl();
          }
        }}
        isOrganizer={isLocalUserOrganizer}
      />
    </DraggableContainer>
  );
}

export default SessionUsersPanel;
