import { useEffect, useState } from 'react';
import { FormProvider, useForm, useWatch } from 'react-hook-form';
import { useNavigate } from 'react-router-dom';

import { IconDeviceMobile } from '@material-hu/icons/tabler';
import Stack from '@material-hu/mui/Stack';
import Typography from '@material-hu/mui/Typography';

import * as HuAuth from '@material-hu/components/composed-components/auth';
import HuAvatar from '@material-hu/components/design-system/Avatar';
import Button from '@material-hu/components/design-system/Buttons/Button';
import HuFormInputOtp from '@material-hu/components/design-system/Inputs/OTP/form';
import HuLink from '@material-hu/components/design-system/Link';

import { OTP_CODE_LENGTH, OTPChannelsLabelAndIcon } from 'src/constants/login';
import {
  useCheckCodeMutation,
  useSendCodeMutation,
} from 'src/hooks/queryHooks/login';
import useGeneralError from 'src/hooks/useGeneralError';
import useStateLocation from 'src/hooks/useStateLocation';
import {
  type OTP,
  type OTPChannels,
  OTPErrors,
  type OTPState,
} from 'src/types/login';
import { useLokaliseTranslation } from 'src/utils/i18n';
import { validateRequired } from 'src/utils/validation';

import Countdown from 'src/components/time/Countdown';

import { loginRoutes } from '../../routes';

export type CheckCodeProps = Pick<OTP, 'receiver'> & {
  channels: OTP['channel'][];
  selectedChannel: OTPChannels;
  onSuccess?: (newSelectedChannel: OTPChannels) => void;
  onError?: (error: OTPErrors) => void;
};

const CheckCode = (props: CheckCodeProps) => {
  const {
    receiver,
    channels,
    selectedChannel,
    onSuccess = () => null,
    onError = () => null,
  } = props;

  const navigate = useNavigate();

  const [showResend, setShowResend] = useState<boolean>(false);

  const { t } = useLokaliseTranslation('authentication');
  const showGeneralError = useGeneralError();
  const state = useStateLocation<OTPState>();

  const form = useForm({
    defaultValues: {
      code: '',
    },
  });

  const {
    handleSubmit,
    reset,
    formState: { isSubmitting, errors },
    setError: setFormError,
    setValue,
  } = form;

  const resetCheck = () => {
    reset();
  };

  const code = useWatch({ control: form.control, name: 'code' });

  const checkCodeMutation = useCheckCodeMutation(
    {
      instanceId: state?.instance?.id,
      instanceName: state?.instance?.name,
      employeeInternalId: state?.employeeInternalId,
      init2faToken: state?.init2faToken,
      channel: selectedChannel,
    },
    {
      onError: err => {
        if (err?.response?.data?.code === OTPErrors.INVALID_CODE) {
          setFormError('code', {
            message: t('INPUT_ERROR_OTP_CHECK_CODE'),
          });
          setValue('code', '');
          return;
        }

        if (err?.response?.data?.code === OTPErrors.MAX_TRIES) {
          resetCheck();
          onError(OTPErrors.MAX_TRIES);
          return;
        }

        showGeneralError(err, t('ERROR_GENERAL_RETRY'));
      },
      onSuccess: res => {
        const { user, instance } = res;
        const needsToResetPassword =
          instance.otpAfterRegularLogin && !user.hasPasswordChanged;

        if (needsToResetPassword) {
          navigate(loginRoutes.updatePassword(), {
            state: res,
          });
        }
        resetCheck();
      },
    },
  );

  const sendMutation = useSendCodeMutation(
    {
      instanceId: state?.instance?.id,
      instanceName: state?.instance?.name,
      employeeInternalId: state?.employeeInternalId,
    },
    {
      onMutate: () => setShowResend(false),
      onError: err => {
        if (err?.response?.data?.code === OTPErrors.MAX_TRIES) {
          resetCheck();
          onError(OTPErrors.MAX_TRIES);
          return;
        }

        setShowResend(true);
        showGeneralError(err, t('ERROR_GENERAL_RETRY'));
      },
    },
  );

  const submit = () => {
    checkCodeMutation.mutate({ code, channel: selectedChannel });
  };

  const handleFinishCount = () => setShowResend(true);

  const handleResend = (newSelectedChannel: OTPChannels) => {
    sendMutation.mutate(newSelectedChannel, {
      onSuccess: () => onSuccess(newSelectedChannel),
    });
  };

  const focusOTP = () => {
    const otpInputs = document.querySelectorAll(
      'input[type="text"], input[type="number"]',
    );
    const firstOtpInput = otpInputs[0] as HTMLInputElement;
    if (firstOtpInput) {
      firstOtpInput.focus();
    }
  };

  useEffect(() => {
    focusOTP();
  }, []);

  const submitting = isSubmitting || checkCodeMutation.isLoading;

  const firstChannel = channels?.[0];
  const secondChannel = channels?.[1];

  const notSelectedChannel =
    selectedChannel === firstChannel ? secondChannel : firstChannel;

  const IconNotSelectedChannel =
    OTPChannelsLabelAndIcon[notSelectedChannel]?.icon;

  return (
    <HuAuth.OTPLayout
      instanceCardProps={{
        name: state?.instance?.name,
        logo: state?.instance?.logo,
      }}
      title={t('OTP_RECEIVE_MESSAGE.NEW_BODY', {
        channel: OTPChannelsLabelAndIcon[selectedChannel].label,
      })}
    >
      <FormProvider {...form}>
        <form onSubmit={handleSubmit(submit)}>
          <Stack sx={{ gap: 3 }}>
            <Stack sx={{ gap: 1 }}>
              <Stack
                sx={{ flexDirection: 'row', alignItems: 'center', gap: 1 }}
              >
                <HuAvatar Icon={IconDeviceMobile} />
                <Typography
                  variant="globalL"
                  fontWeight="fontWeightSemiBold"
                  component="span"
                >
                  {receiver}
                </Typography>
              </Stack>
            </Stack>
            <HuFormInputOtp
              name="code"
              rules={validateRequired()}
              inputOtpProps={{
                label: t('OTP_RECEIVE_MESSAGE.BODY_2'),
                disabled: submitting,
                length: OTP_CODE_LENGTH,
                autoFocus: true,
              }}
            />
            <Stack sx={{ gap: 2, pt: 1 }}>
              <Button
                variant="primary"
                size="large"
                type="submit"
                disabled={
                  submitting || code.length < OTP_CODE_LENGTH || !!errors.code
                }
                loading={submitting}
                fullWidth
                onClick={handleSubmit(submit)}
              >
                {t('OTP_RECEIVE_MESSAGE.BUTTON')}
              </Button>
              {!showResend && (
                <Stack
                  sx={{
                    gap: 1,
                    flexDirection: 'row',
                    alignItems: 'center',
                  }}
                >
                  <Typography variant="globalS">
                    {t('OTP_RECEIVE_MESSAGE.RESEND_IN')}
                  </Typography>
                  <Countdown
                    duration={{ minutes: 1 }}
                    onFinish={handleFinishCount}
                  />
                </Stack>
              )}
              {showResend && (
                <HuLink onClick={() => handleResend(selectedChannel)}>
                  {t('OTP_RECEIVE_MESSAGE.RESEND')}
                </HuLink>
              )}
            </Stack>
            {notSelectedChannel && (
              <Button
                size="large"
                type="submit"
                disabled={sendMutation.isLoading || checkCodeMutation.isLoading}
                loading={sendMutation.isLoading}
                fullWidth
                onClick={() => handleResend(notSelectedChannel)}
                endIcon={
                  sendMutation.isLoading ? null : <IconNotSelectedChannel />
                }
              >
                {t('OTP_SEND_MESSAGE.BUTTON', {
                  channel: OTPChannelsLabelAndIcon[notSelectedChannel].label,
                })}
              </Button>
            )}
          </Stack>
        </form>
      </FormProvider>
    </HuAuth.OTPLayout>
  );
};

export default CheckCode;
