import * as React from 'react';

import { Text, Flex, View, Button } from '@aws-amplify/ui-react';

import { LivenessErrorState } from '../service';
import { LivenessCameraModule } from './LivenessCameraModule';
import {
  createLivenessSelector,
  useLivenessActor,
  useLivenessSelector,
} from '../hooks';
import { isMobileScreen, getLandscapeMediaQuery } from '../utils/device';
import { CancelButton } from '../shared/CancelButton';
import {
  HintDisplayText,
  CameraDisplayText,
  StreamDisplayText,
  ErrorDisplayText,
  defaultErrorDisplayText,
} from '../displayText';
import { LandscapeErrorModal } from '../shared/LandscapeErrorModal';
import { CheckScreenComponents } from '../shared/FaceLivenessErrorModal';

const CHECK_CLASS_NAME = 'liveness-detector-check';

export const selectErrorState = createLivenessSelector(
  (state) => state.context.errorState
);
export const selectIsRecordingStopped = createLivenessSelector(
  (state) => state.context.isRecordingStopped
);

interface LivenessCheckProps {
  hintDisplayText: Required<HintDisplayText>;
  cameraDisplayText: Required<CameraDisplayText>;
  streamDisplayText: Required<StreamDisplayText>;
  errorDisplayText: Required<ErrorDisplayText>;
  components?: CheckScreenComponents;
}

export const LivenessCheck: React.FC<LivenessCheckProps> = ({
  hintDisplayText,
  cameraDisplayText,
  streamDisplayText,
  errorDisplayText,
  components,
}: LivenessCheckProps) => {
  const [state, send] = useLivenessActor();
  const errorState = useLivenessSelector(selectErrorState);
  const isRecordingStopped = useLivenessSelector(selectIsRecordingStopped);

  const isPermissionDenied = state.matches('permissionDenied');
  const isMobile = isMobileScreen();

  const recheckCameraPermissions = () => {
    send({ type: 'RETRY_CAMERA_CHECK' });
  };

  const {
    cameraMinSpecificationsHeadingText,
    cameraMinSpecificationsMessageText,
    cameraNotFoundHeadingText,
    cameraNotFoundMessageText,
    retryCameraPermissionsText,
  } = cameraDisplayText;

  const { cancelLivenessCheckText } = streamDisplayText;

  React.useLayoutEffect(() => {
    if (isMobile) {
      const sendLandscapeWarning = (isLandscapeMatched: boolean) => {
        if (isLandscapeMatched) {
          send({ type: 'MOBILE_LANDSCAPE_WARNING' });
        }
      };

      // Get orientation: landscape media query
      const landscapeMediaQuery = getLandscapeMediaQuery();

      // Send warning based on initial orientation
      sendLandscapeWarning(landscapeMediaQuery.matches);

      // Listen for future orientation changes and send warning
      landscapeMediaQuery.addEventListener('change', (e) => {
        sendLandscapeWarning(e.matches);
      });

      // Remove matchMedia event listener
      return () => {
        landscapeMediaQuery.removeEventListener('change', (e) =>
          sendLandscapeWarning(e.matches)
        );
      };
    }
  }, [isMobile, send]);

  const renderCheck = () => {
    if (errorState === LivenessErrorState.MOBILE_LANDSCAPE_ERROR) {
      const displayText: Required<ErrorDisplayText> = {
        ...defaultErrorDisplayText,
        ...errorDisplayText,
      };
      const {
        landscapeHeaderText,
        portraitMessageText,
        landscapeMessageText,
        tryAgainText,
      } = displayText;
      return (
        <Flex
          backgroundColor="background.primary"
          direction="column"
          textAlign="center"
          alignItems="center"
          justifyContent="center"
          position="absolute"
          width="100%"
        >
          <LandscapeErrorModal
            header={landscapeHeaderText}
            portraitMessage={portraitMessageText}
            landscapeMessage={landscapeMessageText}
            tryAgainText={tryAgainText}
            onRetry={() => {
              send({
                type: 'CANCEL',
              });
            }}
          />
        </Flex>
      );
    } else if (isPermissionDenied) {
      return (
        <Flex
          backgroundColor="background.primary"
          direction="column"
          textAlign="center"
          alignItems="center"
          justifyContent="center"
          width="100%"
          height={480}
        >
          <Text fontSize="large" fontWeight="bold">
            {errorState === LivenessErrorState.CAMERA_FRAMERATE_ERROR
              ? cameraMinSpecificationsHeadingText
              : cameraNotFoundHeadingText}
          </Text>
          <Text maxWidth={300}>
            {errorState === LivenessErrorState.CAMERA_FRAMERATE_ERROR
              ? cameraMinSpecificationsMessageText
              : cameraNotFoundMessageText}
          </Text>
          <Button
            variation="primary"
            type="button"
            onClick={recheckCameraPermissions}
          >
            {retryCameraPermissionsText}
          </Button>
          <View position="absolute" top="medium" right="medium">
            <CancelButton ariaLabel={cancelLivenessCheckText}></CancelButton>
          </View>
        </Flex>
      );
    } else {
      return (
        <LivenessCameraModule
          isMobileScreen={isMobile}
          isRecordingStopped={isRecordingStopped!}
          streamDisplayText={streamDisplayText}
          hintDisplayText={hintDisplayText}
          errorDisplayText={errorDisplayText}
          components={components}
        />
      );
    }
  };

  return (
    <Flex
      direction="column"
      position="relative"
      testId={CHECK_CLASS_NAME}
      className={CHECK_CLASS_NAME}
    >
      {renderCheck()}
    </Flex>
  );
};