import { notify, Wrapper } from '@affine/component';
import {
  AuthInput,
  BackButton,
  ModalHeader,
} from '@affine/component/auth-components';
import { Button } from '@affine/component/ui/button';
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { AuthService } from '@affine/core/modules/cloud';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { useService } from '@toeverything/infra';
import type { FC } from 'react';
import { useCallback, useState } from 'react';

import type { AuthPanelProps } from './index';
import * as styles from './style.css';
import { useCaptcha } from './use-captcha';

export const SignInWithPassword: FC<AuthPanelProps> = ({
  setAuthState,
  setEmailType,
  email,
  onSignedIn,
}) => {
  const t = useAFFiNEI18N();
  const authService = useService(AuthService);

  const [password, setPassword] = useState('');
  const [passwordError, setPasswordError] = useState(false);
  const [verifyToken, challenge] = useCaptcha();
  const [isLoading, setIsLoading] = useState(false);
  const [sendingEmail, setSendingEmail] = useState(false);

  const onSignIn = useAsyncCallback(async () => {
    if (isLoading) return;
    setIsLoading(true);

    try {
      await authService.signInPassword({
        email,
        password,
      });
      onSignedIn?.();
    } catch (err) {
      console.error(err);
      setPasswordError(true);
    } finally {
      setIsLoading(false);
    }
  }, [isLoading, authService, email, password, onSignedIn]);

  const sendMagicLink = useAsyncCallback(async () => {
    if (sendingEmail) return;
    setSendingEmail(true);
    try {
      if (verifyToken) {
        await authService.sendEmailMagicLink(email, verifyToken, challenge);
        setAuthState('afterSignInSendEmail');
      }
    } catch (err) {
      console.error(err);
      notify.error({
        title: 'Failed to send email, please try again.',
      });
      // TODO: handle error better
    }
    setSendingEmail(false);
  }, [sendingEmail, verifyToken, authService, email, challenge, setAuthState]);

  const sendChangePasswordEmail = useCallback(() => {
    setEmailType('changePassword');
    setAuthState('sendEmail');
  }, [setAuthState, setEmailType]);

  return (
    <>
      <ModalHeader
        title={t['com.affine.auth.sign.in']()}
        subTitle={t['com.affine.brand.affineCloud']()}
      />

      <Wrapper
        marginTop={30}
        style={{
          position: 'relative',
        }}
      >
        <AuthInput
          label={t['com.affine.settings.email']()}
          disabled={true}
          value={email}
        />
        <AuthInput
          data-testid="password-input"
          label={t['com.affine.auth.password']()}
          value={password}
          type="password"
          onChange={useCallback((value: string) => {
            setPassword(value);
          }, [])}
          error={passwordError}
          errorHint={t['com.affine.auth.password.error']()}
          onEnter={onSignIn}
        />
        <div
          className={styles.forgetPasswordButtonRow}
          style={{ display: 'none' }} // Not implemented yet.
        >
          <a
            className={styles.linkButton}
            onClick={sendChangePasswordEmail}
            style={{
              color: 'var(--affine-text-secondary-color)',
              fontSize: 'var(--affine-font-sm)',
            }}
          >
            {t['com.affine.auth.forget']()}
          </a>
        </div>
        <div className={styles.sendMagicLinkButtonRow}>
          <a
            data-testid="send-magic-link-button"
            className={styles.linkButton}
            onClick={sendMagicLink}
          >
            {t['com.affine.auth.sign.auth.code.send-email.sign-in']()}
          </a>
        </div>
        <Button
          data-testid="sign-in-button"
          type="primary"
          size="extraLarge"
          style={{ width: '100%' }}
          disabled={isLoading}
          onClick={onSignIn}
        >
          {t['com.affine.auth.sign.in']()}
        </Button>
      </Wrapper>
      <BackButton
        onClick={useCallback(() => {
          setAuthState('signIn');
        }, [setAuthState])}
      />
    </>
  );
};
