/* eslint-disable react/require-default-props */
import { use, useEffect } from 'react';
import PropTypes from 'prop-types';
import bridge from '@arcblock/bridge';
import { useDebounceFn, useMemoizedFn } from 'ahooks';
import pick from 'lodash/pick';
import useBrowser from '@arcblock/react-hooks/lib/useBrowser';
import { isUrl } from '@arcblock/ux/lib/Util';
import { joinURL } from 'ufo';

import { debug } from '../utils';
import { API_DID_PREFIX, BLOCKLET_SERVICE_PATH_PREFIX, DEFAULT_TIMEOUT } from '../constant';
import useSecurity from './hooks/security';
import { SessionContext } from '../Session/context';
import { getWalletDid } from '../User/use-did';

export default function withBridgeCall(Component) {
  const defaultConnectParams = {
    prefix: API_DID_PREFIX,
    checkInterval: 2 * 1000,
    checkTimeout: DEFAULT_TIMEOUT * 1000,
    locale: 'en',
    tokenKey: '_t_',
    encKey: '_ek_',
    baseUrl: '',
    messages: {},
    extraParams: {},
    forceConnected: true,
    enabledConnectTypes: [], // 所有的
    disableSwitchApp: false,
    hideCloseButton: false,
    qrcodeSize: 160,
    options: {},
  };
  function WithBridgeCallComponent(props) {
    const { encryptKey, decrypt } = useSecurity();
    const browser = useBrowser();
    const sessionContext = use(SessionContext);
    const currentUserDid = getWalletDid(sessionContext?.session?.user);
    const params = pick(props, [
      //
      'action',
      'checkTimeout',
      'locale',
      'messages',
      // 'webWalletUrl', arcSphere 中不需要通过 web 登录，不需要此参数
      //
      'baseUrl', // 要写清楚 baseUrl 和 prefix 的处理逻辑
      'prefix',
      'checkInterval',
      'closeTimeout',
      'extraParams',
      'tokenKey',
      'encKey',
      'forceConnected',
      'provider',
      'enabledConnectTypes',
      'disableSwitchApp',
      'hideCloseButton', // 不允许用户关闭这个 connect
      // 'qrcodeSize', // 不应该允许配置？
      'options', // FIXME: @zhanghan 弄清楚参数的字段
      //
      // 'autoConnect',
      // 'saveConnect',
      // 'useSocket', // 后期再考虑实现
      // 'allowWallet',
      // 'showDownload',

      // 函数，需要在这一层进行处理
      // 'onError',
      // 'onSuccess',
      // 'onRecreateSession', // 貌似没有地方用，直接去掉？
      // 'onClose',
    ]);
    const mergedParams = Object.assign({}, defaultConnectParams, params);
    if (mergedParams.forceConnected === true) {
      mergedParams.forceConnected = currentUserDid || true;
    }
    // NOTICE: 传递给 ArcSphere 的 prefix 需要妥善处理 serviceHost 的拼接
    // Web 端的 DID Connect serviceHost 会作为 api 实例的 baseUrl，所以不需要拼接在 prefix 中
    // eslint-disable-next-line react/prop-types
    const serviceHost = props.serviceHost || window?.env?.apiPrefix || window?.blocklet?.prefix || '/';
    if (!isUrl(mergedParams.prefix) && !mergedParams.prefix?.startsWith(BLOCKLET_SERVICE_PATH_PREFIX)) {
      mergedParams.prefix = joinURL(serviceHost, mergedParams.prefix);
    }

    const showOpenArcSphereDIDConnect = browser.arcSphere && props.open && !window.forceOpenConnect;

    const { run: callClientDidConnect } = useDebounceFn(
      useMemoizedFn(async () => {
        debug('bridge call arcDidConnect', props, params, mergedParams);
        try {
          const result = await bridge.callArc('didConnect', { ...mergedParams, [mergedParams.encKey]: encryptKey });
          debug('bridge callArc didConnect: result', result);
          if (result.action === 'error') {
            // eslint-disable-next-line react/prop-types
            props.onError(result.data);
            return;
          }
          if (result.action === 'success') {
            // eslint-disable-next-line react/prop-types
            props.onSuccess(result.data, decrypt);
            return;
          }
          // close | cancel
          // eslint-disable-next-line react/prop-types
          props.onClose(result.data);
          // action 不匹配的时候，什么都不做
        } catch (err) {
          logger.error('Failed to callArc didConnect', err);
        }
      }),
      {
        leading: true,
        wait: 300,
      }
    );

    useEffect(() => {
      if (showOpenArcSphereDIDConnect) {
        debug('WrapConnect call');
        callClientDidConnect();
      }
    }, [callClientDidConnect, showOpenArcSphereDIDConnect]);

    if (showOpenArcSphereDIDConnect) {
      return null;
    }

    return <Component {...props} />;
  }

  WithBridgeCallComponent.propTypes = {
    open: PropTypes.bool,
  };

  return WithBridgeCallComponent;
}
