import { Box } from '@mui/material';
import type { SxProps } from '@mui/material';
import { memo, useEffect, useId, useImperativeHandle, useRef } from 'react';
import { withQuery } from 'ufo';
import { useMemoizedFn, useReactive } from 'ahooks';
import noop from 'lodash/noop';

import { mergeSx } from '../Util/style';
import { callIframe, getCallbackAction } from '../Util/iframe';

function SharedBridge({
  ref = undefined,
  src,
  onClick,
  onLoad = noop,
  sx = {},
  ...rest
}: {
  src: string;
  onClick: (data: { action: string; value: boolean; visitorId?: string; error?: Error }) => void;
  onLoad?: () => void;
  sx?: SxProps;
} & {
  ref?: React.Ref<unknown>;
}) {
  const targetIframeRef = useRef<HTMLIFrameElement>(null);
  const refId = useId();
  const dataId = `shared-bridge_${refId}`;
  const currentState = useReactive<{
    hasInited?: boolean;
    open: boolean;
    hasStorageAccess: boolean;
    origin: string;
    host: string;
    containerEl: HTMLDivElement | null;
  }>({
    hasInited: undefined,
    open: false,
    hasStorageAccess: false,
    containerEl: null,
    get origin() {
      try {
        return new URL(src).origin;
      } catch (error) {
        return src;
      }
    },
    get host() {
      try {
        return new URL(src).host;
      } catch (error) {
        return src;
      }
    },
  });

  useEffect(() => {
    async function handleMessage(event: MessageEvent) {
      const { data } = event;
      if (data.action === getCallbackAction(dataId, 'requestStorageAccess')) {
        currentState.open = false;

        if (!data.value) {
          onClick(data);
          return;
        }

        const { value: visitorId } = await callIframe(targetIframeRef.current as HTMLIFrameElement, 'getVisitorId');
        onClick({ ...data, visitorId });
      } else if (data.action === getCallbackAction(dataId, 'preRequestStorageAccess')) {
        currentState.open = true;
      }
    }

    window.addEventListener('message', handleMessage);
    return () => {
      window.removeEventListener('message', handleMessage);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [onClick, dataId, targetIframeRef?.current]);

  const handleLoad = useMemoizedFn(() => {
    callIframe(targetIframeRef.current as HTMLIFrameElement, 'hasStorageAccess').then(({ value }) => {
      currentState.hasStorageAccess = value;
      currentState.hasInited = true;
    });
    // HACK: 如果目标 bridge 1s 内没有初始化，则认为目标 bridge 不兼容，不进行后续内容的加载
    setTimeout(() => {
      if (currentState.hasInited === undefined) {
        currentState.hasInited = false;
      }
    }, 1000);
    onLoad();
  });

  useImperativeHandle(ref, () => ({
    callIframe(action: string) {
      return callIframe(targetIframeRef.current as HTMLIFrameElement, action);
    },
  }));
  return (
    <Box
      {...rest}
      component="iframe"
      ref={targetIframeRef}
      onLoad={handleLoad}
      data-id={dataId}
      src={withQuery(src, { id: dataId })}
      sx={mergeSx(
        {
          border: 0,
          position: 'absolute',
          top: 0,
          left: 0,
          width: '100%',
          height: '100%',
          cursor: 'pointer',
          backgroundColor: 'transparent',
        },
        sx
      )}
    />
  );
}

export default memo(SharedBridge);
