import PropTypes from 'prop-types';
import { createContext, use, useEffect, useRef, useState } from 'react';
import useBrowser from '@arcblock/react-hooks/lib/useBrowser';
import { useCreation, useLatest, useMemoizedFn, useReactive, useSize, useUpdate } from 'ahooks';
import isUndefined from 'lodash/isUndefined';
import noop from 'lodash/noop';
import { Box } from '@mui/material';
import { translate } from '@arcblock/ux/lib/Locale/util';
import { getCurrentApp, getMaster } from '@arcblock/ux/lib/Util/federated';
import { getDIDMotifInfo } from '@arcblock/did-motif';
import { getDIDColor, isEthereumDid } from '@arcblock/ux/lib/Util';
import { GA_LAST_LOGIN_METHOD } from '@arcblock/ux/lib/withTracker/constant';

import useApps from '../hooks/use-apps';
import { SessionContext } from '../../Session/context';
import translations from '../assets/locale';

const StateContext = createContext({
  isWalletWebview: false,
  isMobile: false,
  matchSmallScreen: false,
  blocklet: null,
});

const { Provider, Consumer } = StateContext;

function StateProvider({
  children,
  blocklet,
  masterBlocklet = undefined,
  action,
  extraParams = {},
  locale = 'en',
  testOnlyBorderColor = undefined,
  ...rest
}) {
  const forceUpdate = useUpdate();
  const [plugins, setPlugins] = useState([]);
  const [showWalletOptions, setShowWalletOptions] = useState(false);
  const [selectedPlugin, setSelectedPlugin] = useState('');
  const pluginsMap = useCreation(() => {
    return new Map(plugins.map((plugin) => [plugin.name, plugin]));
  }, [plugins]);
  const getPlugin = useMemoizedFn((name) => {
    return pluginsMap.get(name);
  });
  const latestActivePlugin = useLatest(selectedPlugin);
  const t = useMemoizedFn((key, data = {}) => {
    return translate(translations, key, locale, 'en', data);
  });
  const sessionContext = use(SessionContext);
  const reactiveState = useReactive({
    sourceAppPid: undefined,
    status: 'created',
    autoActiveWebview: true,
    deeplink: undefined,
    chooseMethod: '',
    retryConnect: noop,
  });
  const staticState = useRef({
    cancelCount: 0,
  });

  const browser = useBrowser();
  const { appInfoList, autoGenerateSourceAppPid, canSwitchApp } = useApps({
    blocklet,
    connectState: reactiveState,
    action,
    sourceAppPid: extraParams?.sourceAppPid,
    enableSwitchApp: extraParams?.forceSwitch || extraParams?.enableSwitchApp,
  });
  const lastLoginMethod = useCreation(() => {
    try {
      return localStorage.getItem(GA_LAST_LOGIN_METHOD);
    } catch (error) {
      return '';
    }
  }, []);

  const rootRef = useRef(null);
  const size = useSize(rootRef);

  const matchSmallScreen = useCreation(() => {
    const width = size?.width || 0;
    return width < 500;
  }, [size?.width]);

  const mergeExtraParams = useCreation(() => {
    if (canSwitchApp) {
      return {
        ...extraParams,
        sourceAppPid: isUndefined(reactiveState.sourceAppPid) ? autoGenerateSourceAppPid : reactiveState.sourceAppPid,
      };
    }

    const masterAppPid = getMaster(blocklet)?.appPid;
    const currentPageMasterAppPid = getMaster(globalThis.blocklet)?.appPid;
    if (sessionContext?.session?.user && (masterAppPid === currentPageMasterAppPid || !masterAppPid)) {
      if (!isUndefined(extraParams?.sourceAppPid)) {
        return extraParams;
      }
      return {
        ...extraParams,
        sourceAppPid: sessionContext.session.user?.sourceAppPid,
      };
    }

    return {
      ...extraParams,
      sourceAppPid: autoGenerateSourceAppPid,
    };
  }, [
    canSwitchApp,
    extraParams,
    reactiveState.sourceAppPid,
    action,
    autoGenerateSourceAppPid,
    sessionContext?.session?.user,
  ]);

  const browserBrand = useCreation(() => {
    const userAgent = window?.navigator?.userAgent;
    if (userAgent.indexOf('Edge') > -1 || userAgent.indexOf('Edg') > -1) {
      return 'edge';
    }
    if (userAgent.indexOf('Chrome') > -1) {
      return 'chrome';
    }
    return 'unknown';
  }, []);

  useEffect(() => {
    reactiveState.sourceAppPid = mergeExtraParams.sourceAppPid;
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [mergeExtraParams.sourceAppPid]);

  const changeStatus = useMemoizedFn((value) => {
    reactiveState.status = value || 'created';
  });

  // currentAppInfo 固定不变，就是当前网站的应用信息
  const currentAppInfo = globalThis.blocklet ? getCurrentApp(blocklet) : globalThis.env;

  const currentAppColor = useCreation(() => {
    if (testOnlyBorderColor) {
      return testOnlyBorderColor;
    }

    const did = currentAppInfo.appPid;
    const isEthDid = isEthereumDid(did);
    const didMotifInfo = isEthDid ? undefined : getDIDMotifInfo(did);
    if (isEthDid) {
      return getDIDColor(did);
    }

    return didMotifInfo.color;
  }, [currentAppInfo.appId, testOnlyBorderColor]);

  // NOTICE: size 的变化频率很高，会触发子组件多次渲染，需要在传递 context 时，排除 size 对它的影响
  const value = useCreation(() => {
    return {
      isWalletWebview: browser.wallet || browser.arcSphere,
      isMobile: browser.mobile.any,
      matchSmallScreen,
      connectState: reactiveState,
      staticState,
      reactiveState,
      appInfoList,
      extraParams: mergeExtraParams,
      blocklet,
      masterBlocklet,
      browserBrand,
      currentAppInfo,
      currentAppColor,

      t,
      locale,
      action,
      changeStatus,
      getPlugin,
      latestActivePlugin,
      plugins,
      setPlugins,
      selectedPlugin,
      setSelectedPlugin,
      forceUpdate,

      // 控制钱包登录的显示
      showWalletOptions,
      setShowWalletOptions,
      // 用于记录上一次登录方式
      lastLoginMethod,
    };
  }, [
    browser.wallet,
    browser.arcSphere,
    browser.mobile.any,
    matchSmallScreen,
    JSON.stringify(reactiveState),
    JSON.stringify(appInfoList),
    JSON.stringify(mergeExtraParams),
    blocklet,
    masterBlocklet,
    locale,
    selectedPlugin,
    forceUpdate,
    currentAppInfo,
    currentAppColor,
  ]);

  return (
    <Provider value={value}>
      <Box {...rest} ref={rootRef}>
        {children}
      </Box>
    </Provider>
  );
}

StateProvider.propTypes = {
  children: PropTypes.any.isRequired,
  blocklet: PropTypes.object.isRequired,
  masterBlocklet: PropTypes.object,
  action: PropTypes.string.isRequired,
  extraParams: PropTypes.object,
  locale: PropTypes.string,
  testOnlyBorderColor: PropTypes.string,
};

function useStateContext() {
  return use(StateContext);
}

export { StateContext, StateProvider, Consumer as StateConsumer, useStateContext };
