import { useEffect, useState } from 'react';
import { useMutation } from 'react-query';

import { useModal } from '@material-hu/hooks/useModal';

import HuDialog from '@material-hu/components/design-system/Dialog';

import phone2 from 'src/assets/sound/phone2.mp3';
import { logEvent } from 'src/config/amplitude';
import { EVENTS_SOCKETS } from 'src/constants/sockets';
import { useAuth } from 'src/contexts/JWTContext';
import { usePageVisibilityContext } from 'src/contexts/PageVisibilityContext';
import { useSocket } from 'src/contexts/SocketContext';
import useGeneralError from 'src/hooks/useGeneralError';
import useHuGoTheme from 'src/hooks/useHuGoTheme';
import useCallRingtone from 'src/pages/dashboard/videoCall/hooks/useCallRingtone';
import IncomingCallModal from 'src/pages/dashboard/videoCall/IncomingCallModal';
import { buildIncomingCallPopupUrl } from 'src/pages/dashboard/videoCall/utils';
import { rejectCall } from 'src/services/streaming';
import { EventName } from 'src/types/amplitude';
import {
  type CallInitialized,
  type CallJoinRequested,
  CallType,
  type InitCallProperties,
} from 'src/types/stream';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { getClientOs, isSafari } from 'src/utils/platform';
import { getUrl } from 'src/utils/stream';

const IncomingCall = () => {
  const socket = useSocket();
  const ThemeProvider = useHuGoTheme();
  const showGeneralError = useGeneralError();
  const { t } = useLokaliseTranslation('calls');
  const {
    component: audioComponent,
    playAudio,
    stopAudio,
  } = useCallRingtone({
    src: phone2,
  });
  const { user } = useAuth();
  const { isVisibleRef } = usePageVisibilityContext();

  const [callProperties, setCallProperties] = useState<
    Partial<InitCallProperties>
  >({
    id: undefined,
    providerCallId: undefined,
    initializationConfig: undefined,
    creator: undefined,
    joinedUserNames: undefined,
    isGroupCall: undefined,
  });

  const { mutateAsync: rejectCallMutation } = useMutation(
    (variables: { callId: string }) => rejectCall(variables.callId),
    {
      onError: error => {
        showGeneralError(error, t('ERROR_REJECT_CALL'));
      },
    },
  );

  useEffect(() => {
    const openModal = (callProps: InitCallProperties) => {
      const isTabVisible = isVisibleRef.current;
      const safari = isSafari();
      const clientOs = getClientOs();
      const isWindows = clientOs === 'Windows';

      const logIncomingCall = (trigger: string, popupOpened?: boolean) => {
        logEvent(EventName.CALLS_INCOMING_CALL_MODAL_OPENED, {
          call_id: callProps.id,
          trigger,
          isTabVisible,
          popupOpened: popupOpened,
          isSafari: safari,
          clientOs,
          receiverUserId: user?.id,
        });
      };

      const showModal = () => {
        showIncomingCallModal({ callProps });
        playAudio();
      };

      if (isTabVisible) {
        showModal();
        logIncomingCall('in_page_modal');
      } else {
        const popupUrl = buildIncomingCallPopupUrl(callProps);
        const width = 600;
        const height = 400;
        const left = Math.round((window.screen.width - width) / 2);
        const top = Math.round((window.screen.height - height) / 2);
        const popup = window.open(
          popupUrl,
          'incomingCallPopup',
          `width=${width},height=${height},top=${top},left=${left}`,
        );

        if (!popup || safari || isWindows) {
          showModal();
          logIncomingCall('popup_fallback_modal', !!popup);
        } else {
          logIncomingCall('popup', true);
        }
      }
    };

    const closeModal = () => {
      closeRejectMemberModal();
      stopAudio();
    };

    const handleCallCreated = (data: CallInitialized) => {
      if (data.creator.id !== user?.id) {
        const callProps: InitCallProperties = {
          id: data.id,
          providerCallId: data.providerCallId,
          initializationConfig: data.initializationConfig,
          creator: {
            ...data.creator,
            name: data.notificationName,
            profilePicture: data.notificationPicture,
          },
          isGroupCall: data.isGroupCall,
        };
        setCallProperties(callProps);
        openModal(callProps);
      }
    };

    const handleCallJoinRequested = (data: CallJoinRequested) => {
      const callProps: InitCallProperties = {
        id: data.id,
        providerCallId: data.providerCallId,
        initializationConfig: data.initializationConfig,
        creator: {
          id: data.inviter.userId,
          name: data.inviter.fullName,
          fullName: data.inviter.fullName,
          profilePicture: data.inviter.profilePicture,
          isCalling: false,
        },
        joinedUserNames: data.joinedUserNames,
      };
      setCallProperties(callProps);
      openModal(callProps);
    };

    socket.listenEvent(EVENTS_SOCKETS.CALL_INITIALIZED, handleCallCreated);
    socket.listenEvent(
      EVENTS_SOCKETS.CALL_JOIN_REQUESTED,
      handleCallJoinRequested,
    );
    socket.listenEvent(EVENTS_SOCKETS.CALL_ENDED, closeModal);
    socket.listenEvent(EVENTS_SOCKETS.CALL_ACCEPTED, closeModal);
    socket.listenEvent(EVENTS_SOCKETS.CALL_REJECTED, closeModal);
    socket.listenEvent(EVENTS_SOCKETS.CALL_MISSED, closeModal);

    return () => {
      socket.closeEvent(EVENTS_SOCKETS.CALL_INITIALIZED, handleCallCreated);
      socket.closeEvent(
        EVENTS_SOCKETS.CALL_JOIN_REQUESTED,
        handleCallJoinRequested,
      );
      socket.closeEvent(EVENTS_SOCKETS.CALL_ENDED, closeModal);
      socket.closeEvent(EVENTS_SOCKETS.CALL_ACCEPTED, closeModal);
      socket.closeEvent(EVENTS_SOCKETS.CALL_REJECTED, closeModal);
      socket.closeEvent(EVENTS_SOCKETS.CALL_MISSED, closeModal);
    };
  }, [socket, user]);

  const handleOnAccept = (id: string, providerCallId: string) => {
    closeRejectMemberModal();
    stopAudio();
    window.open(
      getUrl({
        id,
        providerCallId,
      }),
      id,
    );

    logEvent(EventName.CALLS_CALL_ANSWERED_ACCEPTED, {
      call_type: callProperties.initializationConfig?.cameraEnabled
        ? CallType.VIDEO
        : CallType.AUDIO,
      id: callProperties.id,
      caller_id: callProperties.creator?.id,
    });
  };

  const handleOnCancel = (callId: string) => {
    rejectCallMutation({ callId });
    closeRejectMemberModal();
    stopAudio();
  };

  const {
    modal: incomingCallModal,
    showModal: showIncomingCallModal,
    closeModal: closeRejectMemberModal,
  } = useModal(
    ({ callProps }: { callProps: InitCallProperties }) => (
      <HuDialog
        title={t('INCOMING_CALL')}
        body={
          <IncomingCallModal
            creator={callProps.creator}
            joinedUserNames={callProps.joinedUserNames}
            isGroupCall={callProps.isGroupCall}
            initializationConfig={callProps.initializationConfig}
            onCancel={() => handleOnCancel(callProps.id)}
            onAccept={() =>
              handleOnAccept(callProps.id, callProps.providerCallId)
            }
          />
        }
        onClose={() => {
          handleOnCancel(callProps.id);
        }}
      />
    ),
    {
      fullWidth: true,
      onClose: (_, reason) => {
        if (reason === 'backdropClick') {
          return;
        }
      },
    },
  );

  return (
    <ThemeProvider>
      {incomingCallModal}
      {audioComponent}
    </ThemeProvider>
  );
};

export default IncomingCall;
