import { Loader2 } from "lucide-react"
import { useEffect, useMemo, useRef, useState } from "react"
import { Navigate, useNavigate } from "react-router-dom"
import { toast } from "sonner"

import { sendOtp } from "../../api/users"
import { Button } from "../../components/ui/button"
import { useAuthFlow } from "../../context/AuthFlowContext"
import { useTranslation } from "../../hooks/useTranslation"
import { AuthOtpInput } from "./AuthOtpInput"
import { AuthPanel } from "./AuthPanel"
import { formatCooldown, getApiErrorMessage, getOtpRemainingSeconds, handleThrottleError } from "./utils"

export function ForgotPasswordOtpPage() {
  const navigate = useNavigate()
  const { t, lang } = useTranslation()
  const {
    state,
    setCode,
    setCooldown,
    clearCooldown,
    setOtpDelivery,
    clearOtpDelivery,
  } = useAuthFlow()
  const isRtl = lang === "fa"
  const autoSendStartedRef = useRef(false)
  const [isSendingOtp, setIsSendingOtp] = useState(false)
  const [isContinuing, setIsContinuing] = useState(false)
  const [now, setNow] = useState(Date.now())

  if (!state.forgotPassword.mobile) {
    return <Navigate to="/auth/forgot-password" replace />
  }

  useEffect(() => {
    if (!state.forgotPassword.otpExpiresAt || getOtpRemainingSeconds(state.forgotPassword.otpExpiresAt) <= 0) {
      return
    }

    const timer = window.setInterval(() => {
      setNow(Date.now())
    }, 1000)

    return () => window.clearInterval(timer)
  }, [state.forgotPassword.otpExpiresAt])

  const sendForgotPasswordOtp = async () => {
    setIsSendingOtp(true)
    try {
      const response = await sendOtp(state.forgotPassword.mobile, "forget_password")
      clearCooldown("forgotPasswordOtpSend")
      setCode("forgotPassword", "")
      setOtpDelivery("forgotPassword", response.expires_in_seconds)
      setNow(Date.now())
      toast.success(t.login.toasts.verifySent)
    } catch (error) {
      clearOtpDelivery("forgotPassword")
      if (
        !handleThrottleError({
          error,
          cooldownKey: "forgotPasswordOtpSend",
          setCooldown,
          formatTime: (seconds) => formatCooldown(seconds, isRtl),
          throttleCopy: t.login.throttle,
        })
      ) {
        toast.error(getApiErrorMessage(error, t.login.toasts.failedOtp))
      }
    } finally {
      setIsSendingOtp(false)
    }
  }

  useEffect(() => {
    if (!state.forgotPassword.pendingOtpSend || autoSendStartedRef.current) {
      return
    }

    autoSendStartedRef.current = true
    void sendForgotPasswordOtp()
  }, [state.forgotPassword.pendingOtpSend])

  const otpRemainingSeconds = state.forgotPassword.otpExpiresAt
    ? Math.max(0, Math.ceil((state.forgotPassword.otpExpiresAt - now) / 1000))
    : 0

  const alert = useMemo(() => {
    if (state.cooldowns.forgotPasswordOtpSend <= 0) {
      return null
    }

    const formatted = formatCooldown(state.cooldowns.forgotPasswordOtpSend, isRtl)
    return {
      title: t.login.throttle.title,
      description: t.login.throttle.otpSendMessage(formatted),
    }
  }, [isRtl, state.cooldowns.forgotPasswordOtpSend, t.login.throttle])

  const expiryMessage =
    otpRemainingSeconds > 0
      ? t.login.otpExpiresIn(formatCooldown(otpRemainingSeconds, isRtl))
      : state.forgotPassword.otpExpiresAt
        ? t.login.otpExpired
        : null

  const continueToReset = async (code: string) => {
    if (code.length !== 5) {
      toast.error(t.login.toasts.enterOtp)
      return
    }

    setIsContinuing(true)
    setCode("forgotPassword", code)
    navigate("/auth/forgot-password/password")
  }

  const isBusy = isSendingOtp || isContinuing

  return (
    <AuthPanel
      title={t.login.forgotPasswordVerifyTitle}
      description={t.login.sentCodeDesc(state.forgotPassword.mobile)}
      backTo="/auth/forgot-password"
      backLabel={t.login.back}
      alert={alert}
    >
      <form
        onSubmit={(event) => {
          event.preventDefault()
          void continueToReset(state.forgotPassword.code)
        }}
        className="grid gap-4"
      >
        <AuthOtpInput
          id="forgot-password-otp"
          value={state.forgotPassword.code}
          disabled={isBusy}
          onChange={(value) => setCode("forgotPassword", value)}
          onComplete={(value) => void continueToReset(value)}
        />

        {expiryMessage ? (
          <p className="text-center text-sm text-slate-500 dark:text-slate-400">{expiryMessage}</p>
        ) : null}

        <Button type="submit" className="h-11 w-full" disabled={isBusy}>
          {(isSendingOtp || isContinuing) && <Loader2 className="me-2 h-4 w-4 animate-spin" />}
          {isSendingOtp ? t.login.sendingOtp : t.login.continueToResetPassword}
        </Button>

        <Button
          type="button"
          variant="outline"
          className="h-11 w-full"
          disabled={isBusy || otpRemainingSeconds > 0 || state.cooldowns.forgotPasswordOtpSend > 0}
          onClick={() => void sendForgotPasswordOtp()}
        >
          {state.cooldowns.forgotPasswordOtpSend > 0
            ? t.login.throttle.countdownLabel(formatCooldown(state.cooldowns.forgotPasswordOtpSend, isRtl))
            : t.login.resendOtp}
        </Button>
      </form>
    </AuthPanel>
  )
}
