import { FC, ReactNode, useEffect, useRef, useState } from 'react';
import {
  ActivityIndicator,
  Image,
  Modal,
  ModalProps,
  Platform,
  Pressable,
  SafeAreaView,
  StyleSheet,
  View,
} from 'react-native';
import { WebView } from 'react-native-webview';
import { useConstantCallback } from '../hooks/useConstant';
import { ErrorDisplay } from './ErrorDisplay';
import { KomoEvent } from '../models/KomoEvent';
import { useEmbedMessageHandler } from '../hooks/useEmbedMessageHandler';
import { KomoWebView, KomoWebViewProps } from './KomoWebView';

export const ReactNativeWebViewName = 'ReactNativeWebView';
export const ShareClickUrlParamName = 'shareClickUrl';

type OwnProps = {
  /**
   * Whether the modal is open.
   */
  isOpen: boolean;

  /**
   * Callback for when close is requested.
   */
  onClose: () => void;

  /**
   * Override the default modal header.
   */
  modalHeader?: ReactNode;

  /**
   * Override the url that redirects a user when clicking on a share link
   */
  shareClickUrl?: string;

  /**
   * An identifier for the embedded Komo content to identify where it's being embedded
   */
  appId?: string;

  /**
   * Override the default loading indicator.
   */
  loadingIndicator?: ReactNode;

  /**
   * Override the default modal props.
   */
  modalProps?: Omit<ModalProps, 'visible' | 'onRequestClose'>;

  /**
   * Timeout in milliseconds before showing error state if loading takes too long
   * Defaults to 15000ms (15 seconds)
   */
  loadingTimeoutMs?: number;

  /**
   * Override the default error display
   */
  errorDisplay?: ({ onRetry }: { onRetry: () => void }) => ReactNode;

  /**
   * Callback for when a komo-event is raised in the embedded experience.
   * @param eventData - The KomoEvent data.
   */
  onKomoEvent?: (eventData: KomoEvent) => void;

  /**
   * Callback for when a window message is raised in the embedded experience.
   * Note that komo-events are also window messages, so this callback will be called for komo-events as well.
   * @param eventData - The event data.
   */
  onWindowMessage?: (eventData: any) => void;
};

export type ExperienceModalProps = OwnProps &
  Pick<
    KomoWebViewProps,
    | 'embedUrl'
    | 'embedAuthUrl'
    | 'authPassthroughParams'
    | 'formPrefillValues'
    | 'extensionDataValues'
    | 'iframeProps'
    | 'webViewProps'
    | 'onFileDownload'
  >;

export const ExperienceModal: FC<ExperienceModalProps> = ({
  isOpen,
  onClose,
  embedUrl,
  embedAuthUrl,
  authPassthroughParams,
  modalHeader: modalHeaderOverride,
  shareClickUrl,
  appId,
  formPrefillValues,
  extensionDataValues,
  loadingIndicator,
  modalProps,
  loadingTimeoutMs = 15000,
  errorDisplay,
  onKomoEvent,
  onWindowMessage,
  webViewProps,
  iframeProps,
  onFileDownload,
}) => {
  const [experienceLoading, setExperienceLoading] = useState(true);
  const [showHeader, setShowHeader] = useState(true);
  const [isError, setIsError] = useState(false);
  const [retryCounter, setRetryCounter] = useState(0);
  const webviewRef = useRef<WebView>(null);
  const iframeRef = useRef<HTMLIFrameElement>(null);
  const embedId = appId
    ? `RN::${Platform.OS}::EmbedId::${appId}`
    : `RN::${Platform.OS}::EmbedId::Untitled`;

  const handleClose = useConstantCallback(() => {
    setExperienceLoading(true);
    setIsError(false);
    onClose();
  });

  const handleRetry = useConstantCallback(() => {
    setExperienceLoading(true);
    setIsError(false);
    setRetryCounter((s) => s + 1);
    if (Platform.OS === 'web') {
      iframeRef.current?.contentWindow?.location.reload();
    } else {
      webviewRef.current?.reload();
    }
  });

  const { handleMessage } = useEmbedMessageHandler({
    embedId,
    shareClickUrl,
    isOpen,
    onClose: handleClose,
    onKomoEvent,
    onWindowMessage,
    setExperienceLoading,
    setShowHeader,
    iframeRef,
    webviewRef,
  });

  useEffect(() => {
    if (!isOpen) return;

    // Set new timeout
    const timeout = setTimeout(() => {
      if (experienceLoading) {
        setIsError(true);
      }
    }, loadingTimeoutMs);

    return () => clearTimeout(timeout);
  }, [isOpen, experienceLoading, loadingTimeoutMs, retryCounter]);

  const isLoading = experienceLoading;

  return (
    <Modal
      presentationStyle="overFullScreen"
      animationType="fade"
      transparent={true}
      visible={isOpen}
      onRequestClose={handleClose}
      {...modalProps}
    >
      <SafeAreaView style={styles.modalView}>
        {isLoading && !isError && (
          <View style={styles.loadingIndicator} pointerEvents="none">
            {loadingIndicator || <ActivityIndicator size="large" />}
          </View>
        )}

        {!!modalHeaderOverride && (
          <Pressable
            onPress={handleClose}
            style={styles.headerOverridePressable}
          >
            {modalHeaderOverride}
          </Pressable>
        )}

        {showHeader && !modalHeaderOverride && (
          <View style={styles.modalHeader}>
            <Pressable onPress={handleClose} style={styles.closeButton}>
              <Image source={require('../assets/ArrowLeftIcon.png')} />
            </Pressable>
          </View>
        )}

        {isError &&
          (!errorDisplay ? (
            <View style={styles.errorContainer}>
              <ErrorDisplay onRetry={handleRetry} />
            </View>
          ) : (
            errorDisplay({ onRetry: handleRetry })
          ))}

        {!!embedUrl && !isError && (
          <KomoWebView
            key={`webview-${retryCounter}`}
            embedUrl={embedUrl}
            formPrefillValues={formPrefillValues}
            extensionDataValues={extensionDataValues}
            embedAuthUrl={embedAuthUrl}
            authPassthroughParams={authPassthroughParams}
            iframeProps={iframeProps}
            webViewProps={webViewProps}
            onFileDownload={onFileDownload}
            onMessage={handleMessage}
            iframeRef={iframeRef}
            webviewRef={webviewRef}
            isLoading={isLoading}
          />
        )}
      </SafeAreaView>
    </Modal>
  );
};

const styles = StyleSheet.create({
  modalView: {
    flex: 1,
    backgroundColor: 'rgba(0,0,0,0.9)',
    borderRadius: 0,
    padding: 0,
    alignItems: 'center',
    justifyContent: 'center',
    elevation: 5,
  },
  modalHeader: {
    backgroundColor: 'white',
    width: '100%',
    borderBottomWidth: 1,
    borderBottomColor: '#bfbfbf',
    padding: 12,
  },
  headerOverridePressable: {
    width: '100%',
  },
  closeButton: {
    width: 40,
    padding: 6,
  },
  loadingIndicator: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    justifyContent: 'center',
    alignItems: 'center',
    zIndex: 1000,
  },
  errorContainer: {
    flex: 1,
    width: '100%',
    backgroundColor: '#f8f8f8',
    justifyContent: 'center',
  },
});
