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

import {
  hasScreenShare,
  noopComparator,
  ParticipantsAudio,
  ParticipantView,
  useCallStateHooks,
} from '@stream-io/video-react-sdk';
import { AnimatePresence, motion } from 'motion/react';
import Grid from '@material-hu/mui/Grid';

import useHuSnackbar, {
  type SnackbarKey,
} from '@material-hu/components/design-system/Snackbar';

import { EVENTS_SOCKETS } from 'src/constants/sockets';
import { useSocket } from 'src/contexts/SocketContext';
import { CALL_SNACKBAR_BOTTOM_SPACING } from 'src/pages/dashboard/videoCall/constants';
import useCallParticipants from 'src/pages/dashboard/videoCall/hooks/useCallParticipants';
import useSortParticipants from 'src/pages/dashboard/videoCall/hooks/useSortParticipants';
import useSpeakingTracker from 'src/pages/dashboard/videoCall/hooks/useSpeakingTracker';
import { invalidateParticipantList } from 'src/pages/dashboard/videoCall/queries';
import {
  getAvatarsFromParticipants,
  getCallLayoutGridColumns,
} from 'src/pages/dashboard/videoCall/utils';
import { CallMode, type ParticipantLeft } from 'src/types/stream';
import { useLokaliseTranslation } from 'src/utils/i18n';

import CallLayoutGrid from './layout/CallLayoutGrid';
import CallLayoutGridItem from './layout/CallLayoutGridItem';
import CallShareScreenLayout from './layout/CallShareScreenLayout';
import CustomParticipantView from './layout/CustomParticipantView';
import CustomVideoPlaceholder from './layout/CustomVideoPlaceholder';
import MoreParticipantsItem from './layout/MoreParticipantsItem';

const MAX_DISPLAY_PARTICIPANTS = 12;
const NOOP_SORT_COMPARATOR = noopComparator();

const MotionGridContainer = motion.create(Grid);

const VIEW_TRANSITION = { duration: 0.2 };
const VIEW_FADE = {
  initial: { opacity: 0 },
  animate: { opacity: 1 },
  exit: { opacity: 0 },
};
const GRID_CONTAINER_SX = {
  justifyContent: 'center',
  height: '100%',
};

type OngoingCallProps = {
  callId: string;
  maxParticipantsAllowed: number;
  onEndCall: () => void;
};

const OngoingCall: FC<OngoingCallProps> = props => {
  const { callId, maxParticipantsAllowed, onEndCall } = props;
  const socket = useSocket();
  const { useParticipants, useCallCustomData, useLocalParticipant } =
    useCallStateHooks();

  const { type } = useCallCustomData();

  const localParticipant = useLocalParticipant();

  const { enqueueSnackbar, closeSnackbar } = useHuSnackbar();

  const { t } = useLokaliseTranslation('calls');

  const {
    participantListDrawer,
    showParticipantListDrawer,
    addParticipantModal,
    showAddParticipantModal,
  } = useCallParticipants(callId, maxParticipantsAllowed);

  // stream-io returns the participants in order that was sharing their screens
  // and we want to display the last one that was shared
  const rawParticipants = useParticipants({ sortBy: NOOP_SORT_COMPARATOR });
  const screenShareParticipants = rawParticipants.filter(participant =>
    hasScreenShare(participant),
  );
  const screenShareParticipant =
    screenShareParticipants[screenShareParticipants.length - 1];

  const isSpeakingOverThreshold = useSpeakingTracker(rawParticipants);

  const sortingComparator = useSortParticipants({
    callMode: type,
    hasScreenShare: screenShareParticipants.length > 0,
    isSpeakingOverThreshold,
  });

  const providerParticipants = useMemo(() => {
    if (!sortingComparator) {
      return rawParticipants;
    }
    return [...rawParticipants].sort(sortingComparator);
  }, [rawParticipants, sortingComparator]);

  const hasOverflow = providerParticipants.length > MAX_DISPLAY_PARTICIPANTS;

  const gridColumns = getCallLayoutGridColumns(
    hasOverflow ? MAX_DISPLAY_PARTICIPANTS : providerParticipants.length,
  );

  const participantsInView = providerParticipants
    .slice(0, MAX_DISPLAY_PARTICIPANTS - 1)
    .filter(participant => !participant.isLocalParticipant);

  const extraParticipants = [
    participantsInView[participantsInView.length - 1],
    ...providerParticipants
      .slice(MAX_DISPLAY_PARTICIPANTS - 1)
      .filter(participant => !participant.isLocalParticipant),
  ].filter(Boolean);

  const moreParticipantsAvatars = getAvatarsFromParticipants(extraParticipants);

  // biome-ignore lint/correctness/useExhaustiveDependencies: useHuSnackbar redeclares it on every render, and including it would re-run this effect each render and prematurely close still-visible toasts during the active call
  useEffect(() => {
    const enqueuedKeys: SnackbarKey[] = [];

    const handleUserLeft = (data: ParticipantLeft) => {
      if (callId === data.id && type === CallMode.GROUP) {
        const key = enqueueSnackbar({
          title: t('user_left_call', { name: data.leaverFullName }),
          variant: 'info',
          autoHideDuration: 3000,
          spacing: {
            bottom: CALL_SNACKBAR_BOTTOM_SPACING,
          },
        });
        enqueuedKeys.push(key);
        invalidateParticipantList();
      }
    };

    socket.listenEvent(EVENTS_SOCKETS.CALL_PARTICIPANT_LEFT, handleUserLeft);

    return () => {
      socket.closeEvent(EVENTS_SOCKETS.CALL_PARTICIPANT_LEFT, handleUserLeft);
      enqueuedKeys.forEach(key => {
        closeSnackbar(key);
      });
    };
  }, [callId, closeSnackbar, socket, t, type]);

  return (
    <>
      {participantListDrawer}
      {addParticipantModal}
      <CallLayoutGrid
        handleShowParticipants={showParticipantListDrawer}
        handleShowAddParticipantModal={showAddParticipantModal}
        providerParticipants={rawParticipants}
        screenShareParticipant={screenShareParticipant}
        onEndCall={onEndCall}
      >
        <ParticipantsAudio participants={providerParticipants} />
        <AnimatePresence mode="wait">
          {screenShareParticipant && (
            <MotionGridContainer
              key="screen-share"
              container
              spacing={2}
              sx={GRID_CONTAINER_SX}
              {...VIEW_FADE}
              transition={VIEW_TRANSITION}
            >
              <CallShareScreenLayout
                screenShareParticipant={screenShareParticipant}
                providerParticipants={providerParticipants}
                handleShowParticipants={showParticipantListDrawer}
              />
            </MotionGridContainer>
          )}
          {!screenShareParticipant && (
            <MotionGridContainer
              key="grid"
              container
              spacing={2}
              sx={GRID_CONTAINER_SX}
              {...VIEW_FADE}
              transition={VIEW_TRANSITION}
            >
              <AnimatePresence mode="popLayout">
                {participantsInView.map((participant, index) => {
                  const isLastParticipant =
                    index === participantsInView.length - 1;
                  if (isLastParticipant && hasOverflow) {
                    return null;
                  }
                  return (
                    <CallLayoutGridItem
                      key={participant.sessionId}
                      participant={participant}
                      gridColumns={gridColumns}
                      maxParticipantsInView={MAX_DISPLAY_PARTICIPANTS}
                      providerParticipants={providerParticipants}
                      enableLayoutAnimation={!hasOverflow}
                    >
                      <ParticipantView
                        muteAudio
                        participant={participant}
                        VideoPlaceholder={CustomVideoPlaceholder}
                        trackType="videoTrack"
                        ParticipantViewUI={CustomParticipantView}
                      />
                    </CallLayoutGridItem>
                  );
                })}
                {localParticipant && (
                  <CallLayoutGridItem
                    key={localParticipant.sessionId}
                    participant={localParticipant}
                    gridColumns={gridColumns}
                    maxParticipantsInView={MAX_DISPLAY_PARTICIPANTS}
                    providerParticipants={providerParticipants}
                    enableLayoutAnimation={!hasOverflow}
                  >
                    <ParticipantView
                      muteAudio
                      participant={localParticipant}
                      VideoPlaceholder={CustomVideoPlaceholder}
                      trackType="videoTrack"
                      ParticipantViewUI={CustomParticipantView}
                    />
                  </CallLayoutGridItem>
                )}
                {hasOverflow && (
                  <CallLayoutGridItem
                    key="more-participants"
                    gridColumns={gridColumns}
                    maxParticipantsInView={MAX_DISPLAY_PARTICIPANTS}
                    providerParticipants={providerParticipants}
                  >
                    <MoreParticipantsItem
                      avatars={moreParticipantsAvatars}
                      onClick={showParticipantListDrawer}
                    />
                  </CallLayoutGridItem>
                )}
              </AnimatePresence>
            </MotionGridContainer>
          )}
        </AnimatePresence>
      </CallLayoutGrid>
    </>
  );
};

export default OngoingCall;
