import React, {
  PropsWithChildren,
  useCallback,
  useEffect,
  useState,
} from 'react';
import {useTranslation} from 'react-i18next';
import {shallowEqual} from 'react-redux';
import {LivestreamCallingState} from '@modules/livestream/constants';
import {LivestreamService} from '@modules/livestream/utils';
import {useAppSelector} from '@redux/utils';

import {ConnectionFeedback} from '../ConnectionFeedback';
import {useLivestreamNativeListeners} from './listeners';

interface Props extends PropsWithChildren {
  streamId: string;
  isHost?: boolean;
  cameraEnabled?: boolean;
}

export function LivestreamProvider({
  streamId,
  children,
  isHost = false,
  cameraEnabled,
}: Props) {
  // Default camera to enabled for hosts (preview needed), disabled for viewers
  const effectiveCameraEnabled = cameraEnabled ?? isHost;
  const {t} = useTranslation();
  const [errorMessage, setErrorMessage] = useState<string>();
  const [listenersReady, setListenersReady] = useState(false);

  const {callingState, hlsUrl} = useAppSelector(
    ({livestream}) => ({
      callingState: livestream.livestreamState.callingState,
      hlsUrl: livestream.viewer.hostSetting.hlsUrl,
    }),
    shallowEqual,
  );

  const isJoined = callingState === LivestreamCallingState.JOINED;
  const isJoining = callingState === LivestreamCallingState.JOINING;
  const isIdle = callingState === LivestreamCallingState.IDLE;
  const isLeft = callingState === LivestreamCallingState.LEFT;
  const isExited = callingState === LivestreamCallingState.EXITED;

  const handleError = useCallback((message: string) => {
    setErrorMessage(message);
  }, []);

  const handleListenersReady = useCallback(() => {
    setListenersReady(true);
  }, []);

  useLivestreamNativeListeners({
    onError: handleError,
    onListenersReady: handleListenersReady,
  });

  useEffect(() => {
    if (!streamId || !listenersReady) {
      return;
    }

    if (callingState !== LivestreamCallingState.IDLE) {
      return;
    }

    if (errorMessage) {
      return;
    }

    if (isHost) {
      LivestreamService.startHostLivestream(
        streamId,
        streamId,
        effectiveCameraEnabled,
      );
    } else {
      const isHls = !!hlsUrl;
      LivestreamService.joinViewerLivestream(streamId, streamId, isHls);
    }
  }, [
    streamId,
    isHost,
    effectiveCameraEnabled,
    hlsUrl,
    callingState,
    listenersReady,
    errorMessage,
  ]);

  useEffect(() => {
    return () => {
      LivestreamService.leaveLivestream();
    };
  }, []);

  if (!isJoined && !isLeft && !isExited) {
    const hasError = !!errorMessage;
    return (
      <ConnectionFeedback
        isLoading={!hasError && (isJoining || isIdle)}
        isError={hasError}
        errorText={
          errorMessage ||
          t(
            isHost
              ? 'livestream.errors.call_creation'
              : 'livestream.errors.call_join',
          )
        }
        showBackButton={hasError}
      />
    );
  }

  return <>{children}</>;
}
