"use client"

import { zodResolver } from "@hookform/resolvers/zod"
import { Loader2, SendIcon } from "lucide-react"
import { useContext, useEffect, useRef, useState } from "react"
import { useForm } from "react-hook-form"
import * as z from "zod"

import { useIsHydrated } from "../../../hooks/use-hydrated"
import { useOnSuccessTransition } from "../../../hooks/use-success-transition"
import { AuthUIContext } from "../../../lib/auth-ui-provider"
import { cn, getLocalizedError } from "../../../lib/utils"
import { Button } from "../../ui/button"
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../../ui/form"
import { InputOTP, InputOTPGroup, InputOTPSlot } from "../../ui/input-otp"
import type { AuthFormClassNames } from "../auth-form"
import { authLocalization } from "../../../lib/auth-localization"

export interface PhoneOtpVerificationProps {
  className?: string;
  classNames?: AuthFormClassNames;
  isSubmitting?: boolean;
  redirectTo?: string;
  setIsSubmitting?: (value: boolean) => void
}

export function PhoneOtpVerification({
  className,
  classNames,
  isSubmitting: externalIsSubmitting,
  redirectTo,
  setIsSubmitting,
}: PhoneOtpVerificationProps) {
  const isHydrated = useIsHydrated()
  const phoneNumber = localStorage.getItem('phoneNumber')

  const {
    authClient,
    toast,
    otpLength = 6,
    navigate,
    basePath,
    viewPaths
  } = useContext(AuthUIContext)

  const localization = { ...authLocalization }
  const [isSendingOtp, setIsSendingOtp] = useState(false)
  const [cooldownSeconds, setCooldownSeconds] = useState(0)
  const [otpSent, setOtpSent] = useState(false)
  const { onSuccess, isPending: transitionPending } = useOnSuccessTransition({ redirectTo })

  const formSchema = z.object({
    code: z
      .string()
      .min(1, {
        message: `${localization.oneTimePassword} ${localization.isRequired}`
      })
      .min(6, {
        message: `${localization.oneTimePassword} ${localization.isInvalid}`
      }),
  })

  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      code: "",
    },
  })

  const isSubmitting = externalIsSubmitting || form.formState.isSubmitting || transitionPending

  useEffect(() => {
    setIsSubmitting?.(form.formState.isSubmitting || transitionPending)
  }, [form.formState.isSubmitting, transitionPending, setIsSubmitting])

  // Handle OTP sending cooldown
  useEffect(() => {
    if (cooldownSeconds > 0) {
      const timer = setTimeout(() => {
        setCooldownSeconds(cooldownSeconds - 1)
      }, 1000)
      return () => clearTimeout(timer)
    }
  }, [cooldownSeconds])

  const sendOtp = async () => {
    if (isSendingOtp || cooldownSeconds > 0) return

    try {
      setIsSendingOtp(true)
      await (authClient as any).phoneNumber.sendOtp({
        phoneNumber,
        fetchOptions: { throw: true },
      })
      setCooldownSeconds(60)
      setOtpSent(true)
      toast({
        variant: "success",
        message: localization.otpSent || "Verification code sent successfully",
      })
    } catch (error) {
      toast({
        variant: "error",
        message: getLocalizedError({ error, localization }),
      })
    } finally {
      setIsSendingOtp(false)
    }
  }

  const verifyOtp = async ({ code }: z.infer<typeof formSchema>) => {
    try {
      const data = await authClient.phoneNumber.verify({
        phoneNumber: phoneNumber!,
        code,
        fetchOptions: { throw: true },
      })

      toast({
        variant: "success",
        message: localization.phoneVerified || "Phone number verified successfully",
      })

      if ("token" in data && data.token) {
        await onSuccess();
      } else {
        navigate(`${basePath}/${viewPaths.signIn}${window.location.search}`);
        toast({ variant: "success", message: localization.signUpEmail! });
      }
    } catch (error) {
      toast({
        variant: "error",
        message: getLocalizedError({ error, localization }),
      })
      form.reset()
    }
  }

  if (!isHydrated) {
    return <div>Loading...</div>
  }

  return (
    <div className={cn("space-y-6", className)}>
      <div className="space-y-2 text-center">
        <h2 className="text-2xl font-semibold">
          {localization.verifyPhoneNumber || "Verify Phone Number"}
        </h2>
        <p className="text-muted-foreground">
          {localization.enterVerificationCode || "Enter the 6-digit code sent to"}{' '}
          <span className="font-medium">{phoneNumber}</span>
        </p>
      </div>

      <Form {...form}>
        <form onSubmit={form.handleSubmit(verifyOtp)} className="space-y-6">
          <FormField
            control={form.control}
            name="code"
            render={({ field }) => (
              <FormItem>
                <FormLabel className={classNames?.label}>
                  {localization.verificationCode || "Verification Code"}
                </FormLabel>
                <FormControl>
                  <InputOTP
                    {...field}
                    maxLength={otpLength}
                    onChange={(value) => {
                      field.onChange(value)
                      if (value.length === otpLength) {
                        form.handleSubmit(verifyOtp)()
                      }
                    }}
                    containerClassName={classNames?.otpInputContainer}
                    className={classNames?.otpInput}
                    disabled={isSubmitting}
                  >
                    <InputOTPGroup>
                      {Array.from({ length: otpLength }).map((_, index) => (
                        <InputOTPSlot key={index} index={index} />
                      ))}
                    </InputOTPGroup>
                  </InputOTP>
                </FormControl>
                <FormMessage className={classNames?.error} />
              </FormItem>
            )}
          />

          <div className="grid gap-4">
            <Button
              type="submit"
              disabled={isSubmitting}
              className={cn(classNames?.button, classNames?.primaryButton)}
            >
              {isSubmitting && <Loader2 className="animate-spin" />}
              {localization.verifyPhoneNumber}
            </Button>

            <Button
              type="button"
              variant="outline"
              onClick={sendOtp}
              disabled={cooldownSeconds > 0 || isSendingOtp || isSubmitting}
              className={cn(classNames?.button, classNames?.outlineButton)}
            >
              {isSendingOtp ? (
                <Loader2 className="animate-spin" />
              ) : (
                <SendIcon className={classNames?.icon} />
              )}

              {localization.resendCode}
              {cooldownSeconds > 0 && ` (${cooldownSeconds})`}
            </Button>
          </div>
        </form>
      </Form>
    </div>
  )
}
