import React, { useState, useEffect, useCallback, useRef } from "react";
import { loadStripe } from "@stripe/stripe-js";
import {
  EmbeddedCheckoutProvider,
  EmbeddedCheckout,
} from "@stripe/react-stripe-js";
import { stripeAPI, rentalAPI } from "../services/api";

const stripePromise = loadStripe(
  process.env.REACT_APP_STRIPE_PUBLISHABLE_KEY || ""
);

interface UpdatePaymentMethodProps {
  rentalId: string;
  itemName: string;
  onSuccess: () => void;
  onError: (error: string) => void;
  onCancel: () => void;
}

const UpdatePaymentMethod: React.FC<UpdatePaymentMethodProps> = ({
  rentalId,
  itemName,
  onSuccess,
  onError,
  onCancel,
}) => {
  const [clientSecret, setClientSecret] = useState<string>("");
  const [creating, setCreating] = useState(false);
  const [sessionId, setSessionId] = useState<string>("");
  const [updating, setUpdating] = useState(false);
  const hasCreatedSession = useRef(false);

  // Use refs to avoid recreating handleComplete when props change
  const rentalIdRef = useRef(rentalId);
  const onSuccessRef = useRef(onSuccess);
  const onErrorRef = useRef(onError);
  const sessionIdRef = useRef(sessionId);

  // Keep refs up to date
  rentalIdRef.current = rentalId;
  onSuccessRef.current = onSuccess;
  onErrorRef.current = onError;
  sessionIdRef.current = sessionId;

  const createCheckoutSession = useCallback(async () => {
    // Prevent multiple session creations
    if (hasCreatedSession.current) return;

    try {
      setCreating(true);
      hasCreatedSession.current = true;

      // Create a setup checkout session without rental data
      // (we're updating an existing rental, not creating a new one)
      const response = await stripeAPI.createSetupCheckoutSession({});

      setClientSecret(response.data.clientSecret);
      setSessionId(response.data.sessionId);
    } catch (error: any) {
      hasCreatedSession.current = false; // Reset on error so it can be retried
      onError(
        error.response?.data?.error || "Failed to create checkout session"
      );
    } finally {
      setCreating(false);
    }
  }, [onError]);

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

  // Use useCallback with empty deps - refs provide access to latest values
  const handleComplete = useCallback(() => {
    (async () => {
      try {
        setUpdating(true);

        if (!sessionIdRef.current) {
          throw new Error("No session ID available");
        }

        // Get the completed checkout session
        const sessionResponse = await stripeAPI.getCheckoutSession(
          sessionIdRef.current
        );
        const { status: sessionStatus, setup_intent } = sessionResponse.data;

        if (sessionStatus !== "complete") {
          throw new Error("Payment setup was not completed");
        }

        if (!setup_intent?.payment_method) {
          throw new Error("No payment method found in setup intent");
        }

        // Extract payment method ID - handle both string ID and object cases
        const paymentMethodId =
          typeof setup_intent.payment_method === "string"
            ? setup_intent.payment_method
            : setup_intent.payment_method.id;

        if (!paymentMethodId) {
          throw new Error("No payment method ID found");
        }

        // Update the rental's payment method
        await rentalAPI.updatePaymentMethod(rentalIdRef.current, paymentMethodId);

        onSuccessRef.current();
      } catch (error: any) {
        onErrorRef.current(
          error.response?.data?.error ||
            error.message ||
            "Failed to update payment method"
        );
      } finally {
        setUpdating(false);
      }
    })();
  }, []);

  if (creating) {
    return (
      <div className="text-center py-4">
        <div className="spinner-border mb-3" role="status">
          <span className="visually-hidden">Loading...</span>
        </div>
        <p>Preparing secure checkout...</p>
      </div>
    );
  }

  if (updating) {
    return (
      <div className="text-center py-4">
        <div className="spinner-border mb-3" role="status">
          <span className="visually-hidden">Updating...</span>
        </div>
        <p>Updating payment method...</p>
      </div>
    );
  }

  if (!clientSecret) {
    return (
      <div className="text-center py-4">
        <p className="text-muted">Unable to load checkout</p>
        <button className="btn btn-secondary mt-2" onClick={onCancel}>
          Go Back
        </button>
      </div>
    );
  }

  return (
    <div className="update-payment-method">
      <div className="mb-4">
        <h5>Update Payment Method</h5>
        <p className="text-muted">
          Update your payment method for <strong>{itemName}</strong>. Once
          updated, the owner will be notified and can re-attempt to approve your
          rental request.
        </p>
      </div>

      <div id="embedded-checkout">
        <EmbeddedCheckoutProvider
          key={clientSecret}
          stripe={stripePromise}
          options={{
            clientSecret,
            onComplete: handleComplete,
          }}
        >
          <EmbeddedCheckout />
        </EmbeddedCheckoutProvider>
      </div>

      <div className="mt-3 text-center">
        <button className="btn btn-link text-muted" onClick={onCancel}>
          Cancel
        </button>
      </div>
    </div>
  );
};

export default UpdatePaymentMethod;
