import * as React from 'react';
import {
  Animated,
  StyleSheet,
  useWindowDimensions,
  KeyboardAvoidingView,
  Modal,
  Linking,
} from 'react-native';
import { WebView, type WebViewMessageEvent } from 'react-native-webview';
import { useSafeAreaInsets } from 'react-native-safe-area-context';

import ToldContext from './ToldContext';
import { setReplied, setSeen } from './ToldStorage';
import { Platform } from 'react-native';
import { convertToJSONString } from './utils/hiddenFields';

interface ToldWidgetProps {
  surveyId: string;
  sourceID: string;
  params: string[];
  widgetUrl: string;
}

const transferMessagesToRN = `
  window.addEventListener('message', (e) => {
    window.ReactNativeWebView.postMessage(JSON.stringify(e.data));
  });
  window.console.log = (msg, other = '') => window.ReactNativeWebView.postMessage(JSON.stringify({ type: 'LOG', msg: msg + other }));
`;

export default function ToldWidget({
  surveyId,
  sourceID,
  params,
  widgetUrl,
}: ToldWidgetProps) {
  const insets = useSafeAreaInsets();
  const { height } = useWindowDimensions();
  const webviewRef = React.useRef<WebView>(null);
  const { close, hiddenFields } = React.useContext(ToldContext);
  const [currentHeight, setCurrentHeight] = React.useState(500);
  const [urlModalLink, setUrlModalLink] = React.useState<string | null>(null);

  // Animated values
  const animatedHeight = React.useRef(new Animated.Value(500)).current;
  const animatedOpacity = React.useRef(new Animated.Value(0)).current;

  React.useEffect(() => {
    // When the widget is mounted, we set the survey as seen
    if (surveyId) setSeen(surveyId);
  }, [surveyId]);

  // METHOD: Animate the webview height
  const updateWebviewHeight = React.useCallback(
    (newHeight: number, animated: boolean) => {
      Animated.timing(animatedHeight, {
        toValue: newHeight,
        duration: animated ? 300 : 0,
        useNativeDriver: false,
      }).start();
    },
    [animatedHeight]
  );

  // EVENT: Message received from the webview
  const onMessageReceived = React.useCallback(
    (event: WebViewMessageEvent) => {
      const data = JSON.parse(event.nativeEvent.data);
      const type = data?.type;

      switch (type) {
        case 'LOG':
          if (params.includes('debug')) console.log(`[LOG] ${data.msg}`);
          return;
        case 'IS_LOADED':
          const formattedHiddenFields = convertToJSONString(hiddenFields);
          webviewRef.current?.injectJavaScript(`
            window.postMessage({type: 'OS_TYPE', value: '${Platform.OS.toUpperCase()}'}, '*');
            window.postMessage({type: 'DEVICE_TYPE', value: 'phone'}, '*');
            window.postMessage({type: 'SAFE_AREA', value: '${
              insets.bottom
            }'}, '*');
            window.postMessage({type: 'UPDATE_HIDDENFIELDS', value: '${formattedHiddenFields}'}, '*');
          `);
          break;
        case 'HEIGHT_CHANGE':
          const value = data?.value as number;
          const newHeight = value > height ? height - insets.top : value;
          updateWebviewHeight(newHeight, /*currentHeight > newHeight*/ false);
          if (currentHeight === 500) {
            Animated.timing(animatedOpacity, {
              toValue: 1,
              duration: 300,
              useNativeDriver: false,
            }).start();
          }
          setCurrentHeight(newHeight);
          break;
        case 'LAUNCH_CALENDAR':
          const url = data?.value?.iframeUrl as string;
          // if (url) Linking.openURL(url);
          if (url) setUrlModalLink(url);
          break;
        case 'ADD_COOKIE':
          const reply = data?.reply as boolean;
          if (reply) setReplied(surveyId);
          break;
        case 'CLOSE':
          Animated.timing(animatedOpacity, {
            toValue: 0,
            duration: 125,
            useNativeDriver: false,
          }).start(() => close());
          break;
        default:
          break;
      }
      if (params.includes('debug'))
        console.log(`[MSG RECEIVED] ${event.nativeEvent.data}`);
    },
    [
      params,
      insets,
      height,
      updateWebviewHeight,
      currentHeight,
      surveyId,
      animatedOpacity,
      close,
      hiddenFields,
    ]
  );

  // EVENT: Open a new window
  const onOpenWindow = React.useCallback((event: any) => {
    Linking.openURL(event?.nativeEvent?.targetUrl);
  }, []);

  const onLinkModalClose = React.useCallback(() => {
    setUrlModalLink(null);
  }, []);

  return (
    <Modal transparent visible>
      <KeyboardAvoidingView behavior="padding" style={styles.container}>
        <Animated.View
          style={[
            styles.animatedContainer,
            {
              height: animatedHeight,
              opacity: animatedOpacity,
            },
          ]}
        >
          <WebView
            ref={webviewRef}
            source={{
              uri: `${widgetUrl}/?id=${surveyId}&toldProjectID=${sourceID}`,
            }}
            bounces={false}
            containerStyle={styles.webViewContainer}
            style={styles.webView}
            injectedJavaScript={transferMessagesToRN}
            onMessage={onMessageReceived}
            onOpenWindow={onOpenWindow}
            scrollEnabled={false}
          />
        </Animated.View>
      </KeyboardAvoidingView>
      <Modal
        animationType="slide"
        presentationStyle="pageSheet"
        visible={urlModalLink !== null}
        onRequestClose={onLinkModalClose}
      >
        {urlModalLink && (
          <WebView
            source={{ uri: urlModalLink }}
            containerStyle={styles.webViewContainer}
            onOpenWindow={onOpenWindow}
            scrollEnabled={true}
          />
        )}
      </Modal>
    </Modal>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'column-reverse',
  },
  animatedContainer: {
    flex: 0,
  },
  webViewContainer: {
    flex: 1,
  },
  webView: {
    backgroundColor: 'transparent',
  },
});
