import PropTypes from 'prop-types';
import { CircularProgress } from '@mui/material';
import { useCreation, useMemoizedFn, useReactive } from 'ahooks';
import bridge from '@arcblock/bridge';
import { useBrowser } from '@arcblock/react-hooks';
import noop from 'lodash/noop';
import { useImperativeHandle } from 'react';
import { mergeSx } from '@arcblock/ux/lib/Util/style';
import ProviderIcon from '@arcblock/ux/lib/DIDConnect/provider-icon';
import { LOGIN_PROVIDER, LOGIN_PROVIDER_ICON_SIZE } from '@arcblock/ux/lib/Util/constant';

import { useStateContext } from '../../contexts/state';
import LoginMethodItem from './login-method-item';
import { logger } from '../../../utils';
import useAuthUrl from '../../hooks/auth-url';

export default function MobileLoginItem({
  isTablet = false,
  ref = null,
  tokenState,
  locale,
  tokenKey,
  onClick = noop,
  disableSwitchApp = false,
  ...rest
}) {
  const currentState = useReactive({
    loading: false,
  });
  const { isWalletWebview } = useStateContext();
  const title = 'DID Wallet';
  const browser = useBrowser();

  const callbackUrl = new URL(window.location.href);
  const urlWithParams = useAuthUrl({ disableSwitchApp, tokenState });

  const deepLink = useCreation(() => {
    if (!tokenState.url) {
      return '';
    }

    callbackUrl.searchParams.set('tokenKey', tokenState.token);

    const link = new URL(urlWithParams);
    if (!browser.wallet) {
      link.searchParams.set('callback', encodeURIComponent(callbackUrl));
      link.searchParams.set('callback_delay', 1500);
    }
    link.searchParams.set('locale', locale);
    const encoder = new TextEncoder();
    const currentUrlLength = link.href.length;

    let appInfo = '';
    let memberAppInfo = '';
    try {
      if (tokenState.appInfo) {
        const encoded = encoder.encode(JSON.stringify(tokenState.appInfo));
        appInfo = btoa(String.fromCharCode(...encoded));
      }
      if (tokenState.memberAppInfo) {
        const encoded = encoder.encode(JSON.stringify(tokenState.memberAppInfo));
        memberAppInfo = btoa(String.fromCharCode(...encoded));
      }
      // NOTICE: 当长度过长时，不再添加 appInfo & memberAppInfo
      if (
        currentUrlLength + 'appInfo='.length + appInfo.length + 'memberAppInfo='.length + memberAppInfo.length >
        2000
      ) {
        logger.warn('URL too long, drop appInfo & memberAppInfo', { appInfo, memberAppInfo });
        throw new Error('URL too long');
      }

      if (memberAppInfo) {
        if (appInfo) {
          // 在有 memberAppInfo 的情况下，两个值必须一起写入
          link.searchParams.set('appInfo', appInfo);
          link.searchParams.set('memberAppInfo', memberAppInfo);
        }
      } else if (appInfo) {
        link.searchParams.set('appInfo', appInfo);
      }
    } catch (error) {
      logger.warn('Failed to convert appInfo & memberAppInfo', error);
    }
    return link.href.replace(/^https?:\/\//, 'abt://');
  }, [tokenKey, tokenState.token, tokenState.appInfo, tokenState.memberAppInfo, tokenState.url]);

  const handleWalletConnect = useMemoizedFn(() => {
    currentState.loading = true;
    setTimeout(() => {
      bridge.call('authAction', { action: 'auth', deepLink });
    }, 600);
    setTimeout(() => {
      currentState.loading = false;
    }, 2000);
  });

  // 此处用于在 mobile 浏览器中，用户在点击打开按钮时，直接渲染 scanned 的样式（解决 safari 在页面隐藏后，无法正常发起请求带来的体验较差）
  // 需要在页面再次可见时，将状态设置为正确的值
  const handleOpenDeeplink = useMemoizedFn(() => {
    tokenState.checking = true;
    tokenState.status = 'scanned';
  });

  const modifyProps = {};
  if (!isWalletWebview && browser.mobile.any) {
    modifyProps.component = 'a';
    modifyProps.href = deepLink;
  }

  if (!tokenState.url) {
    modifyProps.sx = {
      cursor: 'not-allowed',
    };
  }

  const handleConnectFn = useMemoizedFn((fallback) => {
    if (!tokenState.url) {
      return;
    }

    if (isWalletWebview) {
      handleWalletConnect();
    } else if (browser.mobile.any || isTablet) {
      handleOpenDeeplink();
    } else {
      fallback();
    }
  });

  const handleConnect = useMemoizedFn(() => {
    handleConnectFn(onClick);
  });

  useImperativeHandle(ref, () => ({
    connect: handleConnectFn,
  }));

  return (
    <LoginMethodItem
      {...rest}
      {...modifyProps}
      sx={mergeSx(rest?.sx, modifyProps?.sx)}
      title={title}
      icon={
        currentState.loading || !tokenState.url ? (
          <CircularProgress
            color="primary"
            size={LOGIN_PROVIDER_ICON_SIZE}
            sx={{
              '& svg': {
                transform: 'scale(0.75)',
              },
            }}
          />
        ) : (
          <ProviderIcon
            provider={LOGIN_PROVIDER.DID_WALLET}
            sx={{
              width: LOGIN_PROVIDER_ICON_SIZE,
              height: LOGIN_PROVIDER_ICON_SIZE,
              transform: 'scale(0.9)',
            }}
          />
        )
      }
      iconScale={1}
      onClick={handleConnect}
    />
  );
}

MobileLoginItem.propTypes = {
  tokenState: PropTypes.object.isRequired,
  tokenKey: PropTypes.string.isRequired,
  locale: PropTypes.string.isRequired,
  onClick: PropTypes.func,
  disableSwitchApp: PropTypes.bool,
  ref: PropTypes.any,
  isTablet: PropTypes.bool,
};
