import { useEffect, useMemo, useState } from "react";
import { Link, useNavigate, useSearchParams } from "react-router-dom";
import { AlertTriangle, ArrowLeft, ArrowRight, CheckCircle2, Command, Loader2 } from "lucide-react";
import { toast } from "sonner";

import { Button } from "../components/ui/button";
import { Input } from "../components/ui/input";
import { SettingsMenu } from "../components/SettingsMenu";
import { ApiError } from "../api/client";
import {
  completeGoogleOAuthSignup,
  getGoogleOAuthFlow,
  sendGoogleOAuthClaimOtp,
  startGoogleLogin,
  verifyGoogleOAuthClaim,
  type GoogleOAuthFlowResponse,
} from "../api/users";
import { useTranslation } from "../hooks/useTranslation";
import { setSessionTokens } from "../lib/session";

type GoogleStep = "loading" | "collect_mobile" | "claim_required" | "error";
type CooldownKey = "otpSend" | "otpVerify";

const PERSIAN_DIGITS = ["۰", "۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹"];

const toPersianDigits = (value: string) =>
  value.replace(/\d/g, (digit) => PERSIAN_DIGITS[Number.parseInt(digit, 10)] ?? digit);

export default function GoogleAuthCallback() {
  const navigate = useNavigate();
  const [searchParams] = useSearchParams();
  const { t, lang } = useTranslation();
  const isRtl = lang === "fa";

  const flow = searchParams.get("flow") ?? "";

  const [step, setStep] = useState<GoogleStep>("loading");
  const [loading, setLoading] = useState(false);
  const [mobile, setMobile] = useState("");
  const [otpCode, setOtpCode] = useState("");
  const [googleEmail, setGoogleEmail] = useState("");
  const [errorMessage, setErrorMessage] = useState("");
  const [cooldowns, setCooldowns] = useState<Record<CooldownKey, number>>({
    otpSend: 0,
    otpVerify: 0,
  });

  useEffect(() => {
    if (!Object.values(cooldowns).some((value) => value > 0)) {
      return;
    }

    const timer = window.setInterval(() => {
      setCooldowns((current) => ({
        otpSend: Math.max(0, current.otpSend - 1),
        otpVerify: Math.max(0, current.otpVerify - 1),
      }));
    }, 1000);

    return () => window.clearInterval(timer);
  }, [cooldowns]);

  const localizeDigits = (value: string) => (isRtl ? toPersianDigits(value) : value);

  const formatCooldown = (seconds: number) => {
    const minutes = Math.floor(seconds / 60);
    const remainingSeconds = seconds % 60;
    const formatted =
      minutes > 0
        ? `${minutes}:${remainingSeconds.toString().padStart(2, "0")}`
        : `${remainingSeconds}s`;
    return localizeDigits(formatted);
  };

  const setCooldown = (key: CooldownKey, seconds: number) => {
    setCooldowns((current) => ({
      ...current,
      [key]: Math.max(current[key], seconds),
    }));
  };

  const handleAuthenticated = (payload: Extract<GoogleOAuthFlowResponse, { status: "authenticated" }>) => {
    setSessionTokens(payload.access, payload.refresh);
    toast.success(t.login.toasts.successLogin);
    navigate("/profile", { replace: true });
  };

  const applyFlowPayload = (payload: GoogleOAuthFlowResponse) => {
    if (payload.status === "authenticated") {
      handleAuthenticated(payload);
      return;
    }

    if (payload.status === "collect_mobile") {
      setGoogleEmail(payload.email);
      setStep("collect_mobile");
      return;
    }

    if (payload.status === "claim_required") {
      setMobile(payload.mobile);
      setStep("claim_required");
    }
  };

  const handleThrottleError = (error: unknown, key: CooldownKey) => {
    if (!(error instanceof ApiError) || error.code !== "throttled") {
      return false;
    }

    const seconds = Math.max(1, error.retryAfterSeconds ?? 0);
    const formattedTime = formatCooldown(seconds);
    setCooldown(key, seconds);

    const message =
      key === "otpSend"
        ? t.login.throttle.otpSendMessage(formattedTime)
        : t.login.throttle.otpLoginMessage(formattedTime);

    toast.error(message, {
      description: t.login.throttle.countdownLabel(formattedTime),
    });

    return true;
  };

  useEffect(() => {
    if (!flow) {
      setErrorMessage(t.login.google.missingFlow);
      setStep("error");
      return;
    }

    let cancelled = false;

    const loadFlow = async () => {
      setLoading(true);
      try {
        const payload = await getGoogleOAuthFlow(flow);
        if (!cancelled) {
          applyFlowPayload(payload);
        }
      } catch (error) {
        if (!cancelled) {
          setErrorMessage(error instanceof Error ? error.message : t.login.google.loadFailed);
          setStep("error");
        }
      } finally {
        if (!cancelled) {
          setLoading(false);
        }
      }
    };

    loadFlow();

    return () => {
      cancelled = true;
    };
  }, [flow]);

  const handleCompleteSignup = async (event: React.FormEvent) => {
    event.preventDefault();
    if (!mobile) {
      toast.error(t.login.toasts.enterMobile);
      return;
    }

    setLoading(true);
    try {
      const payload = await completeGoogleOAuthSignup(flow, mobile);
      applyFlowPayload(payload);
      if (payload.status === "claim_required") {
        toast.success(t.login.google.claimOtpSent);
      }
    } catch (error) {
      toast.error(error instanceof Error ? error.message : t.login.google.completeFailed);
    } finally {
      setLoading(false);
    }
  };

  const handleResendClaimOtp = async () => {
    setLoading(true);
    try {
      await sendGoogleOAuthClaimOtp(flow);
      setCooldowns((current) => ({ ...current, otpSend: 0 }));
      toast.success(t.login.google.claimOtpSent);
    } catch (error) {
      if (!handleThrottleError(error, "otpSend")) {
        toast.error(error instanceof Error ? error.message : t.login.toasts.failedOtp);
      }
    } finally {
      setLoading(false);
    }
  };

  const handleVerifyClaim = async (event: React.FormEvent) => {
    event.preventDefault();
    if (!otpCode) {
      toast.error(t.login.toasts.enterOtp);
      return;
    }

    setLoading(true);
    try {
      const payload = await verifyGoogleOAuthClaim(flow, otpCode);
      setCooldowns((current) => ({ ...current, otpVerify: 0 }));
      applyFlowPayload(payload);
    } catch (error) {
      if (!handleThrottleError(error, "otpVerify")) {
        toast.error(error instanceof Error ? error.message : t.login.toasts.invalidOtp);
      }
    } finally {
      setLoading(false);
    }
  };

  const activeWarning = useMemo(() => {
    if (cooldowns.otpSend > 0) {
      return t.login.throttle.otpSendMessage(formatCooldown(cooldowns.otpSend));
    }
    if (cooldowns.otpVerify > 0) {
      return t.login.throttle.otpLoginMessage(formatCooldown(cooldowns.otpVerify));
    }
    return null;
  }, [cooldowns, isRtl, lang]);

  const BackIcon = isRtl ? ArrowRight : ArrowLeft;

  return (
    <div className="container relative min-h-screen grid flex-col items-center justify-center bg-white transition-colors lg:max-w-none lg:grid-cols-2 lg:px-0 dark:bg-slate-950">
      <div className="absolute inset-e-4 top-4 z-50 md:inset-e-8 md:top-8">
        <SettingsMenu />
      </div>

      <div className="relative hidden h-full flex-col border-e border-slate-200 bg-slate-900 p-10 text-white dark:border-slate-800 dark:bg-slate-900/50 lg:flex">
        <div className="relative z-20 flex items-center gap-2 text-lg font-medium">
          <Command className="h-6 w-6" />
          {t.title || "Qlockify"}
        </div>
        <div className="relative z-20 mt-auto">
          <blockquote className="space-y-2">
            <p className="text-lg">"{t.login.brandingQuote}"</p>
          </blockquote>
        </div>
      </div>

      <div className="flex h-screen items-center justify-center p-8 lg:p-8">
        <div className="mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[420px]">
          <div className="flex flex-col space-y-2 text-center text-slate-900 dark:text-slate-50">
            <div className="mb-4 flex justify-center lg:hidden">
              <Command className="h-8 w-8" />
            </div>
            <h1 className="text-2xl font-semibold tracking-tight">
              {step === "loading" && t.login.google.loadingTitle}
              {step === "collect_mobile" && t.login.google.collectMobileTitle}
              {step === "claim_required" && t.login.google.claimTitle}
              {step === "error" && t.login.google.errorTitle}
            </h1>
            <p className="text-sm text-slate-500 dark:text-slate-400">
              {step === "loading" && t.login.google.loadingDescription}
              {step === "collect_mobile" &&
                t.login.google.collectMobileDescription(googleEmail || "-")}
              {step === "claim_required" && t.login.google.claimDescription(mobile)}
              {step === "error" && (errorMessage || t.login.google.loadFailed)}
            </p>
          </div>

          {activeWarning && (
            <div className="rounded-2xl border border-amber-200 bg-amber-50 px-4 py-3 text-start text-amber-900 shadow-sm dark:border-amber-900/50 dark:bg-amber-950/40 dark:text-amber-100">
              <div className="flex items-start gap-3">
                <AlertTriangle className="mt-0.5 h-4 w-4 shrink-0" />
                <div className="space-y-1">
                  <p className="text-sm font-medium">{t.login.throttle.title}</p>
                  <p className="text-sm">{activeWarning}</p>
                </div>
              </div>
            </div>
          )}

          <div className="grid gap-6">
            {step === "loading" && (
              <div className="rounded-3xl border border-slate-200 bg-white p-8 text-center shadow-sm dark:border-slate-800 dark:bg-slate-900">
                <Loader2 className="mx-auto mb-4 h-8 w-8 animate-spin text-slate-400" />
                <p className="text-sm text-slate-500 dark:text-slate-400">
                  {t.login.google.loadingDescription}
                </p>
              </div>
            )}

            {step === "collect_mobile" && (
              <form onSubmit={handleCompleteSignup} className="grid gap-4">
                <div className="rounded-3xl border border-slate-200 bg-white p-5 shadow-sm dark:border-slate-800 dark:bg-slate-900">
                  <div className="mb-4 flex items-center gap-3">
                    <div className="flex h-10 w-10 items-center justify-center rounded-2xl bg-slate-100 text-slate-700 dark:bg-slate-800 dark:text-slate-200">
                      <CheckCircle2 className="h-5 w-5" />
                    </div>
                    <div className="min-w-0">
                      <p className="text-sm font-medium text-slate-900 dark:text-white">
                        {t.login.google.googleAccount}
                      </p>
                      <p className="truncate text-sm text-slate-500 dark:text-slate-400">{googleEmail}</p>
                    </div>
                  </div>
                  <Input
                    id="google-mobile"
                    placeholder={t.login.mobilePlaceholder}
                    type="tel"
                    dir="ltr"
                    value={mobile}
                    onChange={(event) => setMobile(event.target.value)}
                    maxLength={11}
                    disabled={loading}
                    className={`h-11 ${isRtl ? "text-end" : "text-start"}`}
                  />
                </div>

                <Button type="submit" className="h-11 w-full" disabled={loading}>
                  {loading && <Loader2 className="me-2 h-4 w-4 animate-spin" />}
                  {t.login.google.completeButton}
                </Button>
                <Button type="button" variant="ghost" onClick={() => startGoogleLogin()} className="text-sm text-slate-500 dark:text-slate-400">
                  {t.login.google.restartGoogle}
                </Button>
              </form>
            )}

            {step === "claim_required" && (
              <form onSubmit={handleVerifyClaim} className="grid gap-4">
                <div className="rounded-3xl border border-slate-200 bg-white p-5 shadow-sm dark:border-slate-800 dark:bg-slate-900">
                  <p className="mb-3 text-sm text-slate-500 dark:text-slate-400">
                    {t.login.google.claimDescription(mobile)}
                  </p>
                  <Input
                    id="google-claim-otp"
                    placeholder={t.login.otpPlaceholder}
                    type="text"
                    dir="ltr"
                    value={otpCode}
                    onChange={(event) => setOtpCode(event.target.value)}
                    maxLength={6}
                    disabled={loading}
                    className="h-11 text-center text-lg tracking-widest"
                  />
                </div>

                <Button type="submit" className="h-11 w-full" disabled={loading || cooldowns.otpVerify > 0}>
                  {loading && <Loader2 className="me-2 h-4 w-4 animate-spin" />}
                  {cooldowns.otpVerify > 0
                    ? t.login.throttle.countdownLabel(formatCooldown(cooldowns.otpVerify))
                    : t.login.google.verifyClaimButton}
                </Button>
                <Button
                  type="button"
                  variant="outline"
                  onClick={handleResendClaimOtp}
                  disabled={loading || cooldowns.otpSend > 0}
                  className="h-11"
                >
                  {cooldowns.otpSend > 0
                    ? t.login.throttle.countdownLabel(formatCooldown(cooldowns.otpSend))
                    : t.login.google.resendClaimOtp}
                </Button>
              </form>
            )}

            {step === "error" && (
              <div className="rounded-3xl border border-red-200 bg-red-50 p-6 text-center shadow-sm dark:border-red-900/50 dark:bg-red-950/20">
                <AlertTriangle className="mx-auto mb-3 h-8 w-8 text-red-500" />
                <p className="mb-4 text-sm text-red-700 dark:text-red-200">
                  {errorMessage || t.login.google.loadFailed}
                </p>
                <div className="grid gap-3">
                  <Button type="button" onClick={() => startGoogleLogin()} className="h-11">
                    {t.login.google.restartGoogle}
                  </Button>
                  <Button type="button" variant="ghost" asChild className="text-sm text-slate-500 dark:text-slate-400">
                    <Link to="/auth">
                      <BackIcon className="me-2 h-4 w-4" />
                      {t.login.back}
                    </Link>
                  </Button>
                </div>
              </div>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}
