import {
  type FC,
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react';

import {
  combineComparators,
  pinned,
  publishingAudio,
  publishingVideo,
  useCallStateHooks,
} from '@stream-io/video-react-sdk';
import { type AxiosResponse } from 'axios';
import Stack from '@material-hu/mui/Stack';
import { useTheme } from '@material-hu/mui/styles';

import {
  FullScreenElementType,
  type LiveStream,
  type LiveStreamPost,
  UserTypeStream,
} from 'src/types/stream';

import AutoplayBlockedAlert from 'src/components/dashboard/videoCall/layout/AutoplayBlockedAlert';

import { FULL_SCREEN_COMMENT_WIDTH } from '../../constants';
import { getIsRtmpConnection } from '../../utils';
import useShowControls from '../hooks/useShowControls';
import useVolume from '../hooks/useVolume';

import LiveDetails, { type ReactionsHandlers } from './LiveDetails';
import PlayerContent from './PlayerContent';

const VOLUME_DEFAULT = 0;

type PlayerProps = {
  stream: LiveStream;
  post: LiveStreamPost;
  reactionsHandlers: ReactionsHandlers;
  pollService?: {
    vote: (pollId: number, pollOptionId: number) => Promise<AxiosResponse>;
    key: Array<string | number>;
  };
};

const Player: FC<PlayerProps> = (props: PlayerProps) => {
  const { stream, post, reactionsHandlers, pollService } = props;
  const theme = useTheme();
  const [allowVolume, setAllowVolume] = useState(false);

  const [fullScreenElement, setFullScreenElement] =
    useState<FullScreenElementType>(FullScreenElementType.NONE);

  const [isCaptionsOpen, setIsCaptionsOpen] = useState(false);

  const { handleMouseMove, showControls } = useShowControls();

  const {
    useCallCallingState,
    useCallEndedAt,
    useHasOngoingScreenShare,
    useParticipants,
    useCallCustomData,
    useSpeakerState,
  } = useCallStateHooks();

  const playerContainerRef = useRef<HTMLDivElement>(null);
  const callingState = useCallCallingState();
  const hasOngoingScreenshare = useHasOngoingScreenShare();
  const endedAt = useCallEndedAt();

  const comparator = useMemo(
    () => combineComparators(pinned, publishingVideo, publishingAudio),
    [],
  );
  const participants = useParticipants({ sortBy: comparator });

  const { isRtmpConnection: customDataIsRtmpConnection } = useCallCustomData();
  const isRtmpConnection = getIsRtmpConnection(
    stream.streamSource,
    customDataIsRtmpConnection,
  );
  const { speaker } = useSpeakerState();

  const speakerUpdate = useCallback(
    (newValue: number) => {
      speaker.setVolume(newValue);
    },
    [speaker],
  );

  const volumeHandlers = useVolume(VOLUME_DEFAULT, speakerUpdate);

  useEffect(() => {
    if (!endedAt) return;
    if (document.fullscreenElement) document.exitFullscreen().catch(() => {});
    setFullScreenElement(FullScreenElementType.NONE);
  }, [endedAt]);

  useEffect(() => {
    const handleFullscreenChange = () => {
      if (!document.fullscreenElement) {
        setFullScreenElement(prev =>
          prev === FullScreenElementType.FULL
            ? FullScreenElementType.SEMI
            : prev,
        );
      }
    };
    window.addEventListener('fullscreenchange', handleFullscreenChange);
    return () =>
      window.removeEventListener('fullscreenchange', handleFullscreenChange);
  }, []);

  const toggleFullscreen = useCallback(() => {
    if (fullScreenElement === FullScreenElementType.FULL) {
      setFullScreenElement(FullScreenElementType.SEMI);
      document.exitFullscreen();
    } else if (fullScreenElement === FullScreenElementType.SEMI) {
      playerContainerRef.current?.requestFullscreen();
      setFullScreenElement(FullScreenElementType.FULL);
    } else {
      setFullScreenElement(FullScreenElementType.SEMI);
    }
  }, [fullScreenElement]);

  const hostParticipant = isRtmpConnection
    ? participants.find(participant =>
        participant.userId.split('-').includes(UserTypeStream.RTMP),
      )
    : participants.find(
        participant =>
          participant.roles.includes(UserTypeStream.HOST) &&
          !participant.userId.split('-').includes(UserTypeStream.RTMP),
      );

  const handlePlayerClick = () => {
    setAllowVolume(true);
  };

  const participantViewHeight: Record<FullScreenElementType, string> = {
    [FullScreenElementType.SEMI]: '100vh',
    [FullScreenElementType.FULL]: '100%',
    [FullScreenElementType.NONE]: 'unset',
  };

  const player = (
    <Stack
      ref={playerContainerRef}
      onClick={handlePlayerClick}
      onMouseMove={handleMouseMove}
      sx={{
        position: 'relative',
        display: 'flex',
        flexDirection: 'column',
        gap: '4px',
        height:
          fullScreenElement === FullScreenElementType.FULL ? '100%' : undefined,
        '& .str-video__video': {
          objectFit: 'contain',
          width:
            fullScreenElement === FullScreenElementType.SEMI
              ? `calc(100% - ${FULL_SCREEN_COMMENT_WIDTH})`
              : '100%',
          background: theme.palette.new.text.neutral.default,
        },
        '& .str-video__participant-details': {
          display: 'none',
        },
        '& .str-video__participant-view': {
          position: 'relative',
          height: participantViewHeight[fullScreenElement],
          maxHeight:
            fullScreenElement === FullScreenElementType.NONE ? '620px' : '100%',
          maxWidth: '100%',
          borderRadius:
            fullScreenElement === FullScreenElementType.NONE ? 2 : 0,
          aspectRatio: 16 / 9,
          justifyContent:
            fullScreenElement === FullScreenElementType.SEMI
              ? 'flex-start'
              : 'center',
        },
        '& .str-video__participant-view--speaking': {
          outline: 'none',
        },
      }}
    >
      <PlayerContent
        callingState={callingState}
        hostParticipant={hostParticipant}
        allowVolume={allowVolume}
        fullScreenElement={fullScreenElement}
        toggleFullscreen={toggleFullscreen}
        onClose={() => {
          if (document.fullscreenElement) document.exitFullscreen();
          setFullScreenElement(FullScreenElementType.NONE);
        }}
        hasOngoingScreenshare={hasOngoingScreenshare}
        showControls={showControls}
        stream={stream}
        post={post}
        pollService={pollService}
        isCaptionsOpen={isCaptionsOpen}
        setIsCaptionsOpen={setIsCaptionsOpen}
        volumeHandlers={volumeHandlers}
      />
      <AutoplayBlockedAlert variant="livestream" />
      {fullScreenElement === FullScreenElementType.SEMI && (
        <LiveDetails
          post={post}
          reactionsHandlers={reactionsHandlers}
          fullScreenContainer={playerContainerRef.current}
        />
      )}
    </Stack>
  );

  return (
    <Stack
      sx={
        fullScreenElement !== FullScreenElementType.NONE
          ? {
              position: 'fixed',
              top: 0,
              left: 0,
              width: '100vw',
              height: '100vh',
              zIndex: theme.zIndex.modal,
              bgcolor: 'new.background.layout.default',
            }
          : {}
      }
    >
      {player}
    </Stack>
  );
};

export default Player;
