"use client";

import { useAction } from "convex/react";
import { ConvexError } from "convex/values";
import { useCallback, useEffect, useRef, useState } from "react";
import { Alert, Button, Card, Separator, Spinner } from "@heroui/react";
import {
  CheckoutProvider,
  PaymentElement,
  useCheckout,
} from "@stripe/react-stripe-js/checkout";

import { api } from "../../../../../../convex/_generated/api";
import type { Id } from "../../../../../../convex/_generated/dataModel";
import { stripePromise } from "@/lib/stripe";
import type { PaymentStepProps } from "@/lib/checkout/types";

type PaymentState =
  | { phase: "initialising" }
  | { phase: "ready"; clientSecret: string }
  | { phase: "error"; message: string };

export function PaymentStep({
  shipmentObjectId,
  selectedShippingRate,
  addressId,
  sessionId,
  onBack,
}: PaymentStepProps) {
  const createSession = useAction(api.stripeActions.createCheckoutSession);
  const [state, setState] = useState<PaymentState>({ phase: "initialising" });
  const fetchIdRef = useRef(0);

  const initSession = useCallback(async () => {
    const id = ++fetchIdRef.current;
    setState({ phase: "initialising" });

    try {
      const result = await createSession({
        addressId: addressId as Id<"addresses">,
        shipmentObjectId,
        shippingRate: selectedShippingRate,
        sessionId,
      });

      if (id !== fetchIdRef.current) return;
      setState({ phase: "ready", clientSecret: result.clientSecret });
    } catch (err) {
      if (id !== fetchIdRef.current) return;

      let message: string;
      if (err instanceof ConvexError && typeof err.data === "string") {
        message = err.data;
      } else if (err instanceof Error) {
        message = err.message;
      } else {
        message = "Unable to prepare payment. Please try again.";
      }
      setState({ phase: "error", message });
    }
  }, [createSession, addressId, shipmentObjectId, selectedShippingRate, sessionId]);

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

  if (state.phase === "initialising") {
    return <PaymentSkeleton />;
  }

  if (state.phase === "error") {
    return (
      <div className="flex flex-col gap-4">
        <Alert status="danger" role="alert">
          <Alert.Indicator />
          <Alert.Content>
            <Alert.Title>Payment setup failed</Alert.Title>
            <Alert.Description>{state.message}</Alert.Description>
          </Alert.Content>
        </Alert>
        <div className="flex flex-col gap-2 md:flex-row">
          <Button
            variant="primary"
            className="w-full bg-[#236f6b] font-medium text-white md:w-auto"
            onPress={initSession}
          >
            Retry
          </Button>
          <Button
            variant="ghost"
            className="w-full md:w-auto"
            onPress={onBack}
          >
            Back to review
          </Button>
        </div>
      </div>
    );
  }

  return (
    <CheckoutProvider
      stripe={stripePromise}
      options={{ clientSecret: state.clientSecret }}
    >
      <CheckoutForm onBack={onBack} onSessionExpired={initSession} />
    </CheckoutProvider>
  );
}

// ─── Checkout Form (inside CheckoutProvider) ────────────────────────────────

function CheckoutForm({
  onBack,
  onSessionExpired,
}: {
  onBack: () => void;
  onSessionExpired: () => void;
}) {
  const checkoutState = useCheckout();
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [errorMessage, setErrorMessage] = useState<string | null>(null);

  if (checkoutState.type === "loading") {
    return <PaymentSkeleton />;
  }

  if (checkoutState.type === "error") {
    const isExpiry =
      checkoutState.error.message?.toLowerCase().includes("expir") ?? false;

    return (
      <div className="flex flex-col gap-4">
        <Alert status="danger" role="alert">
          <Alert.Indicator />
          <Alert.Content>
            <Alert.Title>
              {isExpiry ? "Session expired" : "Payment session error"}
            </Alert.Title>
            <Alert.Description>
              {isExpiry
                ? "Your payment session has expired. Please try again to start a new secure session."
                : (checkoutState.error.message ||
                  "Something went wrong loading the payment form. Please try again.")}
            </Alert.Description>
          </Alert.Content>
        </Alert>
        <div className="flex flex-col gap-2 md:flex-row">
          <Button
            variant="primary"
            className="w-full bg-[#236f6b] font-medium text-white md:w-auto"
            onPress={onSessionExpired}
          >
            Try again
          </Button>
          <Button
            variant="ghost"
            className="w-full md:w-auto"
            onPress={onBack}
          >
            Back to review
          </Button>
        </div>
      </div>
    );
  }

  const { checkout } = checkoutState;

  const handleSubmit = async () => {
    setIsSubmitting(true);
    setErrorMessage(null);

    const result = await checkout.confirm();
    if (result.type === "error") {
      setErrorMessage(result.error.message);
    }
    setIsSubmitting(false);
  };

  const subtotal = checkout.total.subtotal;
  const shippingAmount = checkout.total.shippingRate;
  const total = checkout.total.total;

  return (
    <div className="flex flex-col gap-6">
      <div className="grid grid-cols-1 gap-6 lg:grid-cols-[1fr,340px] lg:items-start">
        {/* Left column: payment form */}
        <div className="flex flex-col gap-4">
          <h3 className="font-[family-name:var(--font-fraunces)] text-lg font-semibold">
            Payment details
          </h3>
          <PaymentElement />

          {errorMessage && (
            <Alert status="danger" role="alert">
              <Alert.Indicator />
              <Alert.Content>
                <Alert.Description>{errorMessage}</Alert.Description>
              </Alert.Content>
            </Alert>
          )}
        </div>

        {/* Right column: order summary */}
        <div className="lg:sticky lg:top-8 lg:self-start">
          <Card className="rounded-lg p-4">
            <Card.Content className="flex flex-col gap-4 p-0">
              <section aria-label="Order summary">
                <h2 className="mb-3 font-[family-name:var(--font-fraunces)] text-lg font-semibold">
                  Summary
                </h2>
                <dl className="flex flex-col gap-3">
                  <div className="flex items-center justify-between text-sm">
                    <dt className="text-default-500">
                      Items ({checkout.lineItems.length})
                    </dt>
                    <dd className="font-semibold text-foreground">
                      {subtotal.amount}
                    </dd>
                  </div>
                  <div className="flex items-center justify-between text-sm">
                    <dt className="text-default-500">Shipping</dt>
                    <dd className="font-semibold text-foreground">
                      {shippingAmount.amount}
                    </dd>
                  </div>
                  <Separator />
                  <div className="flex items-center justify-between">
                    <dt className="font-medium text-foreground">Total</dt>
                    <dd className="text-lg font-bold text-[#236f6b]">
                      {total.amount}
                    </dd>
                  </div>
                </dl>
              </section>

              <div className="flex flex-col gap-2">
                <Button
                  variant="primary"
                  className="w-full bg-[#236f6b] font-medium text-white"
                  size="lg"
                  onPress={handleSubmit}
                  isDisabled={isSubmitting || !checkout.canConfirm}
                  isPending={isSubmitting}
                >
                  {isSubmitting ? "Processing…" : `Pay ${total.amount}`}
                </Button>
                <Button
                  variant="ghost"
                  className="w-full md:w-auto"
                  onPress={onBack}
                  isDisabled={isSubmitting}
                >
                  Back to review
                </Button>
              </div>
            </Card.Content>
          </Card>
        </div>
      </div>
    </div>
  );
}

// ─── Payment Skeleton ─────────────────────────────────────────────────────────

function PaymentSkeleton() {
  return (
    <div className="flex flex-col items-center gap-4 py-12" role="status">
      <Spinner size="lg" />
      <p className="text-sm text-default-500">Preparing secure payment…</p>
    </div>
  );
}
