"use client";

import { useAction } from "convex/react";
import { ConvexError } from "convex/values";
import { useCallback, useEffect, useRef, useState } from "react";
import { api } from "../../../../../convex/_generated/api";
import type { Id } from "../../../../../convex/_generated/dataModel";
import type { CheckoutShippingRateResult } from "./types";

/**
 * One-shot hook that fetches a shipping rate from Shippo when `addressId` is non-null.
 *
 * Fires automatically on mount (or when addressId/sessionId change).
 * Provides `retry()` to manually re-fetch after a transient failure.
 */
export function useShippingRate(
  addressId: string | null,
  sessionId: string | undefined,
): {
  result: CheckoutShippingRateResult | null;
  isLoading: boolean;
  error: string | null;
  retry: () => void;
} {
  const getShippingRateAction = useAction(api.checkoutActions.getShippingRate);

  const [result, setResult] = useState<CheckoutShippingRateResult | null>(null);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const fetchIdRef = useRef(0);

  const fetchRate = useCallback(async () => {
    if (!addressId) return;

    const id = ++fetchIdRef.current;
    setIsLoading(true);
    setError(null);
    setResult(null);

    try {
      const rateResult = await getShippingRateAction({
        addressId: addressId as Id<"addresses">,
        sessionId,
      });

      if (id !== fetchIdRef.current) return;
      setResult(rateResult as CheckoutShippingRateResult);
    } catch (err) {
      if (id !== fetchIdRef.current) return;

      let message: string;
      if (err instanceof ConvexError && typeof err.data === "string") {
        message = err.data;
      } else {
        message = "Unable to calculate shipping rates. Please try again.";
      }
      setError(message);
    } finally {
      if (id === fetchIdRef.current) {
        setIsLoading(false);
      }
    }
  }, [addressId, sessionId, getShippingRateAction]);

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

  const retry = useCallback(() => {
    fetchRate();
  }, [fetchRate]);

  return { result, isLoading, error, retry };
}
