import React, { cloneElement, FC, useEffect, useRef } from 'react';
import { View } from 'react-native';
import Logger from '../core/logging/logger';
import CSQMethodFilter from '../csq/CSQMethodFilter';
import { CSWebViewProps } from '../types/types';
import { hasOnlyOneChild, mergeCallbacks } from '../utils/utils';
import { injectWebView, removeWebViewInjection } from './webView';

/**
 * CSWebView is a wrapper around the React Native WebView component.
 *
 * @param children - The child webview component to render.
 */

export const CSWebView: FC<CSWebViewProps> = ({ children }) => {
  const nativeTag = useRef<number | null | undefined>(undefined);
  const injectedWebViewTag = useRef<number | null | undefined>(undefined);
  const hasOneChild = hasOnlyOneChild(children);

  useEffect(() => {
    CSQMethodFilter.warnIfDisabled('default', 'CSWebView');

    return () => {
      if (injectedWebViewTag.current != null) {
        removeWebViewInjection(injectedWebViewTag.current);
      }
    };
  }, []);

  useEffect(() => {
    if (children && !hasOneChild) {
      Logger.error(
        'CSWebView component expects exactly 1 child, but received multiple. Ensure that only a single child element is passed'
      );
    }
  }, [children]);

  // We need to clone React Native WebView so we can inject the webview onLoadEnd
  const renderChildWebView = () => {
    if (children && hasOneChild) {
      const userOnLoadEnd = (children as React.ReactElement<any>).props
        .onLoadEnd;
      const originalApplicationNameForUserAgent = (children as React.ReactElement<any>).props.applicationNameForUserAgent;

      const webViewApplicationNameForUserAgent = originalApplicationNameForUserAgent
        ? `${originalApplicationNameForUserAgent} CS_WebView`
        : `CS_WebView`;

      // We need to be sure to call our internal onLoadEnd method which is the responsible of starting
      // the injection process but also we need to keep React Native WebView onLoadEnd prop that could
      // have been defined by the user
      const mergeOnLoadEnd = mergeCallbacks(inject, userOnLoadEnd);

      return cloneElement(children, {
        ...(children as React.ReactElement<any>).props,
        onLoadEnd: mergeOnLoadEnd,
        applicationNameForUserAgent: webViewApplicationNameForUserAgent,
      });
    }
  };

  const inject = (event: any) => {
    nativeTag.current = event.nativeEvent.target;
    if (nativeTag.current && nativeTag.current !== injectedWebViewTag.current) {
      injectWebView(nativeTag.current);
      injectedWebViewTag.current = nativeTag.current;
    }
  };

  return <View style={{ flex: 1 }}>{renderChildWebView()}</View>;
};
