import { useEffect, useState } from 'react';
import {
  Alert,
  Anchor,
  Button,
  Center,
  Divider,
  Group,
  PinInput,
  Stack,
  Text,
  ThemeIcon,
  Title,
} from '@mantine/core';
import { IconArrowRight, IconShieldLock } from '@tabler/icons-react';
import { Controller, useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { useNavigate, useLocation } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import { useApiMutation } from '@ema-platform/api';
import { notify, useErrorHandler } from '@ema-platform/ui';
import { AuthShell } from '../components/AuthShell';
import { useAuthConfig } from '../AuthConfig';
import { loginSuccess, setUser } from '../store/auth.slice';
import type { AuthUser, LoginPayload } from '../types/auth.types';

const CODE_LENGTH = 6;
const RESEND_SECONDS = 30;

const schema = z.object({
  verificationCode: z
    .string()
    .length(CODE_LENGTH, { message: `Enter the ${CODE_LENGTH}-digit code` }),
});

type FormValues = z.infer<typeof schema>;

export function OTPVerificationPage() {
  const navigate = useNavigate();
  const location = useLocation();
  const { loginRedirectPath } = useAuthConfig();
  const dispatch = useDispatch();
  const state = location.state as
    | { email?: string; phoneNumber?: string; mode?: 'mfa' }
    | null;
  const email = state?.email ?? '';
  const phoneNumber = state?.phoneNumber ?? '';
  /** Second factor at sign-in, as opposed to the phone-number verification. */
  const isMfa = state?.mode === 'mfa';

  const [verifyTrigger, { isLoading: loading }] = useApiMutation<LoginPayload>();
  const [resendTrigger, { isLoading: resending }] = useApiMutation();
  const [meTrigger] = useApiMutation<AuthUser>();
  const [secondsLeft, setSecondsLeft] = useState(RESEND_SECONDS);
  const [serverError, setServerError] = useState<string | null>(null);
  const { handleError } = useErrorHandler();

  const {
    control,
    handleSubmit,
    formState: { errors },
  } = useForm<FormValues>({
    resolver: zodResolver(schema),
    defaultValues: { verificationCode: '' },
  });

  useEffect(() => {
    if (secondsLeft <= 0) return;
    const id = setInterval(() => setSecondsLeft((s) => s - 1), 1000);
    return () => clearInterval(id);
  }, [secondsLeft]);

  const onSubmit = async (values: FormValues) => {
    try {
      if (isMfa) {
        const data = await verifyTrigger({
          url: '/auth/mfa-verify',
          method: 'POST',
          body: { email, otp: values.verificationCode },
        }).unwrap();

        dispatch(loginSuccess(data));
        const me = await meTrigger({ url: '/auth/me', method: 'GET' }).unwrap();
        dispatch(setUser(me));

        navigate(loginRedirectPath);
        return;
      }

      await verifyTrigger({
        url: '/auth/verify-phone-number',
        method: 'PATCH',
        body: { email, phoneNumber, verificationCode: values.verificationCode },
      }).unwrap();

      notify.success('Phone number verified successfully');
      navigate(loginRedirectPath);
    } catch (err: unknown) {
      setServerError(handleError(err));
    }
  };

  const handleResendOtp = async () => {
    if (secondsLeft > 0 || resending) return;
    try {
      await resendTrigger({
        url: '/auth/generate-verification-code',
        method: 'PATCH',
        body: { email, phoneNumber, type: 'verify-phone-number' },
      }).unwrap();

      notify.success('Verification code resent to your email');
      setSecondsLeft(RESEND_SECONDS);
      setServerError(null);
    } catch (err: unknown) {
      setServerError(handleError(err));
    }
  };

  return (
    <AuthShell
      brandTitle="One last step to secure your account."
      brandSubtitle="We use a one-time code to confirm it's really you before granting access."
    >
      <Stack gap="lg">
        <ThemeIcon size={56} radius="md" variant="light" color="emaPrimary">
          <IconShieldLock size={30} />
        </ThemeIcon>

        <div>
          <Title order={2} fz={30}>
            Verify your account
          </Title>
          <Text c="dimmed" mt={6}>
            A verification code has been sent to{' '}
            <Text span fw={600} c="dark">
              {email || 'your email'}
            </Text>
            . Enter it below to continue.
          </Text>
        </div>

        {serverError && (
          <Alert variant="light" color="red" withCloseButton onClose={() => setServerError(null)}>
            {serverError}
          </Alert>
        )}

        <form onSubmit={handleSubmit(onSubmit)}>
          <Stack gap="md">
            <Controller
              control={control}
              name="verificationCode"
              render={({ field }) => (
                <Stack gap={6} align="center">
                  <PinInput
                    length={CODE_LENGTH}
                    type="alphanumeric"
                    inputMode="text"
                    oneTimeCode
                    size="md"
                    gap="sm"
                    error={!!errors.verificationCode}
                    value={field.value}
                    onChange={field.onChange}
                    onComplete={() => handleSubmit(onSubmit)()}
                  />
                  {errors.verificationCode?.message && (
                    <Text c="red" size="sm">
                      {errors.verificationCode.message}
                    </Text>
                  )}
                </Stack>
              )}
            />
            <Button
              type="submit"
              loading={loading}
              fullWidth
              size="md"
              rightSection={<IconArrowRight size={18} />}
            >
              Verify
            </Button>
          </Stack>
        </form>

        {/* Sign-in has not happened yet under MFA, so there is nothing to skip
            to — and the resend endpoint below only regenerates phone-verification
            codes. A fresh MFA code means logging in again. */}
        {!isMfa && (
          <>
            <Divider
              label="Having trouble?"
              labelPosition="center"
              variant="dashed"
            />

            <Button
              variant="light"
              fullWidth
              size="md"
              onClick={() => navigate(loginRedirectPath)}
            >
              Skip verification for now
            </Button>

            <Center>
              <Group justify="center" gap={6}>
                <Text size="sm" c="dimmed">
                  Didn&apos;t receive a code?
                </Text>
                {secondsLeft > 0 ? (
                  <Text size="sm" c="dimmed" fw={600}>
                    Resend in {secondsLeft}s
                  </Text>
                ) : (
                  <Anchor
                    size="sm"
                    fw={600}
                    onClick={handleResendOtp}
                    style={
                      resending ? { pointerEvents: 'none', opacity: 0.6 } : undefined
                    }
                  >
                    Resend code
                  </Anchor>
                )}
              </Group>
            </Center>
          </>
        )}
      </Stack>
    </AuthShell>
  );
}
