import LoadingMask from '@arcblock/ux/lib/LoadingMask';
import { Box, CircularProgress, TextField, Typography } from '@mui/material';
import { useCreation, useInterval, useMemoizedFn, useReactive } from 'ahooks';
import PropTypes from 'prop-types';
import { joinURL, withQuery } from 'ufo';
import Toast from '@arcblock/ux/lib/Toast';
import VerificationCode from '@arcblock/ux/lib/VerificationCode';
import { useEffect } from 'react';
import noop from 'lodash/noop';
import ProviderIcon from '@arcblock/ux/lib/DIDConnect/provider-icon';

import BackButton from '../../components/back-button';
import ActionButton from '../../components/action-button';
import { useStateContext } from '../../contexts/state';
import { BLOCKLET_SERVICE_PATH_PREFIX, CHECK_STATUS_INTERVAL, VERIFY_CODE_LENGTH } from '../../../constant';
import { createAxios, debug } from '../../../utils';

export default function EmailPlaceholder({
  fallback = null,
  state,
  forceUpdate = noop,
  onSuccess = noop,
  t: rawT = noop,
}) {
  const { setSelectedPlugin, locale, connectState, action, extraParams } = useStateContext();
  const t = useMemoizedFn((key, data = {}) => {
    return rawT(key, data, locale);
  });
  const api = useCreation(() => {
    return createAxios({
      baseURL: joinURL(state.baseUrl, BLOCKLET_SERVICE_PATH_PREFIX, '/api/user'),
    });
  }, [state.baseUrl]);

  const currentState = useReactive({
    email: '',
    code: '',
    codeId: '',
    defaultVerifyMode: 'magicLink',
    verifyMode: 'magicLink', // magicLink, code
    loadingSendCode: false,
    loadingVerifyCode: false,
    error: '',
  });

  const reset = useMemoizedFn(() => {
    currentState.email = '';
    currentState.code = '';
    currentState.codeId = '';
    currentState.verifyMode = currentState.defaultVerifyMode;
    currentState.loadingSendCode = false;
    currentState.loadingVerifyCode = false;
    currentState.error = '';
  });

  const sendCode = useMemoizedFn(async () => {
    if (!currentState.email || !currentState.email.trim()) {
      currentState.error = t('emailRequired');
      return;
    }

    // 检查邮箱格式
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(currentState.email)) {
      currentState.error = t('emailInvalid');
      return;
    }
    currentState.error = '';

    try {
      currentState.loadingSendCode = true;
      let useMagicLink = false;
      // FIXME: @zhanghan 暂时只允许登录时使用 magicLink，否则其他的事件无法调用正确的回调
      if (['login'].includes(action)) {
        // FIXME: @zhanghan 如果 sourceAppPid 存在，则不使用 magicLink，暂无法获得正确的 magicLink 地址
        if (!connectState.sourceAppPid) {
          useMagicLink = true;
        }
      }
      const { data } = await api.post(withQuery('/email/sendCode', { locale }), {
        email: currentState.email,
        sourceAppPid: connectState.sourceAppPid,
        useMagicLink,
      });
      currentState.verifyMode = currentState.defaultVerifyMode;
      currentState.codeId = data.id;
      state.status = 'sending';
    } catch (error) {
      const errorMessage = error?.response?.data?.error || error?.message;
      state.status = 'error';
      state.error = errorMessage;
    } finally {
      currentState.loadingSendCode = false;
      forceUpdate();
    }
  });
  const verifyCode = useMemoizedFn(async () => {
    if (currentState.code.length !== VERIFY_CODE_LENGTH) {
      return;
    }

    try {
      currentState.loadingVerifyCode = true;
      const { data: loginResult } = await api.post(withQuery('/email/login', { locale }), {
        ...extraParams,
        action,
        code: currentState.code,
        sourceAppPid: connectState.sourceAppPid,
      });
      debug('Email login succeed (use code)', { loginResult });
      await onSuccess(
        {
          ...loginResult,
          encrypted: false,
        },
        (val) => val
      );
      state.status = 'succeed';
    } catch (error) {
      const errorMessage = error?.response?.data || error?.message;
      Toast.error(errorMessage);
      debug('Email login failed (use code)', { error });
    } finally {
      currentState.loadingVerifyCode = false;
      forceUpdate();
    }
  });
  const verifyMagicToken = useMemoizedFn(async () => {
    state.status = 'verifying';
    forceUpdate();
    try {
      const { data: loginResult } = await api.post(withQuery('/email/login', { locale }), {
        ...extraParams,
        action,
        magicToken: state.magicToken,
      });
      debug('Email login succeed (use magic link)', { loginResult });
      await onSuccess(
        {
          ...loginResult,
          encrypted: false,
        },
        (val) => val
      );
      state.status = 'succeed';
    } catch (error) {
      const errorMessage = error?.response?.data || error?.message;
      state.status = 'error';
      state.error = errorMessage;
      debug('Email login failed (use magic link)', { error });
    }
    forceUpdate();
  });

  const shouldPoll =
    currentState.verifyMode === 'magicLink' &&
    state.status === 'sending' &&
    // 如果正在校验验证码，则不轮询状态
    !currentState.loadingVerifyCode &&
    currentState.codeId;

  const checkStatus = useMemoizedFn(async () => {
    if (!shouldPoll) {
      return;
    }
    try {
      const { data } = await api.get('/email/status', {
        params: {
          codeId: currentState.codeId,
        },
      });
      if (data.verified) {
        state.status = 'succeed';
        reset();
        await onSuccess({ encrypted: false }, (val) => val);
      }
    } catch (error) {
      // 只做记录
      console.error('check status error', error);
    }
    forceUpdate();
  });

  useInterval(checkStatus, shouldPoll ? CHECK_STATUS_INTERVAL : undefined);

  useEffect(() => {
    reset();
    // FIXME: @zhanghan 暂不支持子站进行统一登录时使用 magicLink 登录
    if (connectState.sourceAppPid || !['login'].includes(action)) {
      currentState.defaultVerifyMode = 'code';
    }
    if (state.magicToken) {
      verifyMagicToken();
    }
    // 由于存在 email 插件被重置的情况，所以需要监听 state 是否被重新赋值来执行 init 操作
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [state]);

  let content = null;
  if (state.status === 'creating') {
    content = (
      <>
        <Typography
          variant="body2"
          sx={{
            textAlign: 'center',
            color: 'text.secondary',
          }}>
          {t('emailPlaceholder')}
        </Typography>
        <TextField
          name="email"
          fullWidth
          type="email"
          variant="outlined"
          label={t('email')}
          placeholder={t('emailPlaceholder')}
          size="small"
          value={currentState.email}
          onChange={(e) => {
            currentState.email = e.target.value;
          }}
          onKeyDown={(e) => {
            if (e.key === 'Enter') {
              sendCode(currentState.email);
            }
          }}
          sx={{
            maxWidth: 320,
            '& .MuiOutlinedInput-root': {
              borderRadius: 1,
            },
          }}
          error={!!currentState.error}
          helperText={currentState.error}
          slotProps={{
            htmlInput: {
              sx: {
                boxSizing: 'content-box !important',
              },
            },
          }}
        />
        <Box sx={{ display: 'flex', gap: 1 }}>
          <BackButton
            onClick={() => {
              state.reset();
              setSelectedPlugin();
            }}
          />
          <ActionButton
            sx={{
              color: 'primary.main',
              borderColor: 'primary.light',
            }}
            disabled={currentState.loadingSendCode}
            onClick={() => {
              sendCode(currentState.email);
            }}>
            {currentState.loadingSendCode ? <CircularProgress color="inherit" size={14} sx={{ mr: 1 }} /> : null}
            {t('sendCode')}
          </ActionButton>
        </Box>
      </>
    );
  } else if (state.status === 'sending') {
    content = (
      <>
        <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
          <Typography variant="body2" sx={{ textAlign: 'center', color: 'text.secondary' }}>
            {currentState.verifyMode === 'magicLink' ? (
              <>
                {t('verifyEmail')}
                <br />
                {t('orUseCodePlaceholder')}
              </>
            ) : (
              t('codePlaceholder')
            )}
          </Typography>
          <>
            {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
            {/* 暂时保留代码，防止后期需要再使用 */}
            {/* <Link
              underline="none"
              variant="caption"
              component="button"
              sx={{ mb: 2 }}
              onClick={() => {
                currentState.verifyMode = 'code';
                forceUpdate();
              }}>
              {t('useCode')}
            </Link>
            <BackButton
              onClick={() => {
                state.status = 'creating';
                forceUpdate();
              }}
            /> */}
          </>
        </Box>
        <>
          <VerificationCode
            code={currentState.code}
            onChange={(code) => {
              currentState.code = code;
            }}
            onComplete={() => {
              verifyCode();
            }}
          />
          <Box sx={{ display: 'flex', gap: 1 }}>
            <BackButton
              onClick={() => {
                currentState.code = '';
                state.status = 'creating';
                forceUpdate();
              }}
            />
            <ActionButton
              sx={{
                color: 'primary.main',
                borderColor: 'primary.light',
              }}
              disabled={currentState.loadingVerifyCode}
              onClick={() => {
                verifyCode();
              }}>
              {currentState.loadingVerifyCode ? <CircularProgress color="inherit" size={14} sx={{ mr: 1 }} /> : null}
              {t('confirm')}
            </ActionButton>
          </Box>
        </>
      </>
    );
  } else {
    return fallback;
  }

  return (
    <Box
      sx={{
        display: 'flex',
        flexDirection: 'column',
        alignItems: 'center',
        justifyContent: 'center',
        gap: 2,
        pb: 1,
      }}>
      <LoadingMask size={52} borderRadius={12}>
        <ProviderIcon provider="email" />
      </LoadingMask>
      {content}
    </Box>
  );
}

EmailPlaceholder.propTypes = {
  fallback: PropTypes.any,
  state: PropTypes.object.isRequired,
  forceUpdate: PropTypes.func,
  onSuccess: PropTypes.func,
  t: PropTypes.func,
};
