import { Navigate } from '@tanstack/react-router';
import React, { useState } from 'react';
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';

import { otpVerify, verifyCredentials, switchAccount } from '@/actions/auth';
import { BigCard } from '@/components/big-card';
import Button from '@/components/ui/button';
import Card, { CardBody, CardHeader, CardTitle } from '@/components/ui/card';
import Form from '@/components/ui/form';
import FormActions from '@/components/ui/form-actions';
import FormGroup from '@/components/ui/form-group';
import Input from '@/components/ui/input';
import { useAppDispatch } from '@/hooks/use-app-dispatch';

const messages = defineMessages({
  otpCodeHint: {
    id: 'login.fields.otp_code_hint',
    defaultMessage:
      'Enter the two-factor code generated by your phone app or use one of your recovery codes',
  },
  otpCodeLabel: { id: 'login.fields.otp_code_label', defaultMessage: 'Two-factor code:' },
  otpLoginFail: { id: 'login.otp_log_in.fail', defaultMessage: 'Invalid code, please try again.' },
});

interface IOtpAuthForm {
  mfa_token: string;
  small?: boolean;
}

const OtpAuthForm: React.FC<IOtpAuthForm> = ({ mfa_token, small }) => {
  const dispatch = useAppDispatch();
  const intl = useIntl();

  const [isLoading, setIsLoading] = useState(false);
  const [shouldRedirect, setShouldRedirect] = useState(false);
  const [codeError, setCodeError] = useState<string | boolean>('');

  const getFormData = (form: any) =>
    Object.fromEntries(Array.from(form).map((i: any) => [i.name, i.value]));

  const handleSubmit = (event: React.FormEvent) => {
    const { code } = getFormData(event.target);
    dispatch(otpVerify(code, mfa_token))
      .then(({ access_token }) => {
        setCodeError(false);
        return dispatch(verifyCredentials(access_token));
      })
      .then((account: Record<string, any>) => {
        setShouldRedirect(true);
        return dispatch(switchAccount(account.id));
      })
      .catch(() => {
        setIsLoading(false);
        setCodeError(true);
      });
    setIsLoading(true);
    event.preventDefault();
  };

  if (shouldRedirect) return <Navigate to='/' replace />;

  const form = (
    <Form onSubmit={handleSubmit}>
      <FormGroup
        labelText={intl.formatMessage(messages.otpCodeLabel)}
        hintText={intl.formatMessage(messages.otpCodeHint)}
        errors={codeError ? [intl.formatMessage(messages.otpLoginFail)] : []}
      >
        <Input name='code' type='text' autoComplete='one-time-code' autoFocus required />
      </FormGroup>

      <FormActions>
        <Button theme='primary' type='submit' disabled={isLoading}>
          <FormattedMessage id='login.sign_in' defaultMessage='Sign in' />
        </Button>
      </FormActions>
    </Form>
  );

  if (small) {
    return (
      <Card>
        <CardHeader>
          <CardTitle
            title={<FormattedMessage id='login.otp_log_in' defaultMessage='OTP Login' />}
          />
        </CardHeader>
        <CardBody>{form}</CardBody>
      </Card>
    );
  }

  return (
    <BigCard title={<FormattedMessage id='login.otp_log_in' defaultMessage='OTP Login' />}>
      {form}
    </BigCard>
  );
};

export { OtpAuthForm as default };
