import { type FC, useCallback, useEffect, useRef, useState } from 'react';
import { Helmet } from 'react-helmet-async';
import { FormProvider, useForm } from 'react-hook-form';
import { useMutation } from 'react-query';

import { useCall, useCallStateHooks } from '@stream-io/video-react-sdk';
import { IconX } from '@material-hu/icons/tabler';
import IconButton from '@material-hu/mui/IconButton';
import Stack from '@material-hu/mui/Stack';
import Typography from '@material-hu/mui/Typography';

import { logEvent } from 'src/config/amplitude';
import { EVENTS_SOCKETS } from 'src/constants/sockets';
import { useAuth } from 'src/contexts/JWTContext';
import { useSocket } from 'src/contexts/SocketContext';
import useHuGoTheme from 'src/hooks/useHuGoTheme';
import HostLiveSteamLayout from 'src/pages/dashboard/liveStream/HostLiveStream/components/HostLiveStreamLayout';
import { useStreamActions } from 'src/pages/dashboard/liveStream/hooks/useStreamActions';
import { EventName } from 'src/types/amplitude';
import {
  type LiveStream as LiveStreamType,
  StreamStatus,
  VideoOrigin,
} from 'src/types/stream';
import { formatTitle } from 'src/utils/helmetUtils';
import { useLokaliseTranslation } from 'src/utils/i18n';

import { useStreamDestination } from '../hooks/useStreamDestination';
import { invalidatePollDataQueries } from '../queries';

import useLeaveLive from './hooks/useLeaveLive';

type LiveStreamProps = {
  stream: LiveStreamType;
};

const LiveStream: FC<LiveStreamProps> = props => {
  const { stream } = props;

  const [postId, setPostId] = useState<number>();
  const [streamStatus, setStreamStatus] = useState(StreamStatus.Idle);

  const { t } = useLokaliseTranslation();
  const { user } = useAuth();
  const HugoThemeProvider = useHuGoTheme();
  const socket = useSocket();

  const call = useCall();
  const { useIsCallLive } = useCallStateHooks();
  const isLive = useIsCallLive();
  const wasEverLive = useRef(false);

  const joinLiveStreamMutation = useMutation(
    (variables: { postId: number }) =>
      destinationActions.joinLiveStream(variables.postId),
    {
      onSuccess: response => {
        socket.emitEvent(EVENTS_SOCKETS.JOIN_ROOM, {
          userId: user?.id.toString(),
          ticketId: response.data.ticketId,
        });
      },
    },
  );

  const {
    destination,
    details: destinationDetails,
    actions: destinationActions,
  } = useStreamDestination();

  const form = useForm({
    defaultValues: {
      videoOrigin: VideoOrigin.WEBCAM,
      bodyHtml: '',
      commentsEnabled: true,
      sendNotification: true,
      streamKey: stream.rtmpKey,
      streamServer: stream.rtmpUrl,
      captionsEnabled: stream.captionsEnabled,
      captionsLanguage: stream.captionsLanguage,
      hlsEnabled: stream.hlsEnabled,
      screenShareContentHint: {
        default: true,
        motion: false,
        text: false,
        detail: false,
      },
    },
    mode: 'onChange',
  });

  useEffect(() => {
    if (isLive) {
      // Track that the SDK confirmed the stream was live at least once, to avoid a false finish on startup
      wasEverLive.current = true;
    }

    // if the call is not live and the stream is streaming, means that the streamed was ended because of network issues
    // in our backend we `call.stopLive()` after 2 minutes of disconection
    if (
      wasEverLive.current &&
      !isLive &&
      streamStatus === StreamStatus.Streaming
    ) {
      setStreamStatus(StreamStatus.Finished);
    }
  }, [isLive, streamStatus]);

  const {
    bodyHtml,
    sendNotification,
    commentsEnabled,
    captionsEnabled,
    hlsEnabled,
    videoOrigin,
  } = form.watch();

  const { goLiveMutate, stopLiveMutate, isLoadingGoLive, isLoadingStopLive } =
    useStreamActions({
      bodyHtml,
      streamId: stream?.id,
      sendNotification,
      commentsEnabled,
      onStart: response => {
        const { data } = response;
        logEvent(EventName.LIVESTREAM_STARTED, {
          userId: user?.id,
          postID: data.id,
          captionsEnabled: captionsEnabled,
          hlsEnabled: hlsEnabled,
          recordingEnabled: stream.recordingEnabled,
          livestreamID: stream.id,
          destination: destination,
          destinationID: destinationDetails?.id || '',
        });
        setPostId(data.id);
        joinLiveStreamMutation.mutate({ postId: data.id });
        setStreamStatus(StreamStatus.Streaming);
        call?.update({
          custom: {
            isRtmpConnection: videoOrigin === VideoOrigin.SOFTWARE_STREAMING,
          },
        });
      },
      onStartError: () => {
        setStreamStatus(StreamStatus.Idle);
      },
      onFinish: () => {
        setStreamStatus(StreamStatus.Finished);
        call?.endCall();
        invalidatePollDataQueries(stream.id);
      },
    });

  const onFinish = () => {
    stopLiveMutate();
    logEvent(EventName.LIVESTREAM_ENDED, {
      userId: user?.id,
      postID: postId,
      livestreamID: stream.id,
      destination: destination,
      destinationID: destinationDetails ? destinationDetails.id : '',
    });
  };

  const { confirmLeaveModal } = useLeaveLive(onFinish, streamStatus);

  const onHardwareReady = useCallback(() => {
    if (videoOrigin === VideoOrigin.SOFTWARE_STREAMING) {
      call?.camera.disable();
      call?.microphone.disable();
    } else {
      call?.camera.enable();
      call?.microphone.enable();
    }
  }, [call, videoOrigin]);

  const handleGoBack = () => {
    destinationActions.invalidateQueries();
    destinationActions.goToDestination();
  };

  const onStartPress = () => setStreamStatus(StreamStatus.Preparing);

  const onCancel = () => setStreamStatus(StreamStatus.Idle);

  const onReady = () => {
    goLiveMutate();
    setStreamStatus(StreamStatus.Connecting);
  };

  return (
    <HugoThemeProvider>
      <FormProvider {...form}>
        <Helmet>
          <title>{formatTitle(t('LIVE_STREAM'))}</title>
        </Helmet>
        <Stack
          sx={{
            background: theme => theme.palette.new.background.layout.default,
            minHeight: '100vh',
          }}
        >
          {call && (
            <>
              {confirmLeaveModal}
              <Stack
                sx={{
                  width: '100%',
                  position: 'fixed',
                  zIndex: 10,
                  alignItems: 'center',
                  flexDirection: 'row',
                  justifyContent: 'space-between',
                  backgroundColor: theme =>
                    theme.palette.new.background.layout.tertiary,
                  py: theme => theme.spacing(1.5),
                  px: theme => theme.spacing(3),
                }}
              >
                <Typography
                  variant="globalL"
                  fontWeight="fontWeightSemiBold"
                  color="text.primary"
                >
                  {t('LIVE_STREAM')}
                </Typography>
                <IconButton
                  onClick={handleGoBack}
                  sx={{
                    color: theme => theme.palette.new.text.neutral.default,
                  }}
                >
                  <IconX />
                </IconButton>
              </Stack>
              <HostLiveSteamLayout
                postId={postId}
                streamId={stream.id}
                streamStatus={streamStatus}
                onReady={onReady}
                onFinish={onFinish}
                onHardwareReady={onHardwareReady}
                onStartPress={onStartPress}
                onCancel={onCancel}
                onGoBack={handleGoBack}
                isLoadingGoLive={isLoadingGoLive}
                isLoadingStopLive={isLoadingStopLive}
              />
            </>
          )}
        </Stack>
      </FormProvider>
    </HugoThemeProvider>
  );
};

export default LiveStream;
