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 EmbeddedStripeCheckoutProps {
  rentalData: any;
  onSuccess: () => void;
  onError: (error: string) => void;
}

const EmbeddedStripeCheckout: React.FC<EmbeddedStripeCheckoutProps> = ({
  rentalData,
  onSuccess,
  onError,
}) => {
  const [clientSecret, setClientSecret] = useState<string>("");
  const [creating, setCreating] = useState(false);
  const [sessionId, setSessionId] = useState<string>("");
  const hasCreatedSession = useRef(false);

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

  // Keep refs up to date
  rentalDataRef.current = rentalData;
  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;
      
      const response = await stripeAPI.createSetupCheckoutSession({
        rentalData
      });
      
      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);
    }
  }, [rentalData, onError]);

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

  // Use useCallback with empty deps - refs provide access to latest values
  const handleComplete = useCallback(() => {
    // For embedded checkout, we need to retrieve the session to get payment method
    (async () => {
      try {
        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");
        }

        // Create the rental with the payment method ID
        const rentalPayload = {
          ...rentalDataRef.current,
          stripePaymentMethodId: paymentMethodId
        };

        await rentalAPI.createRental(rentalPayload);
        onSuccessRef.current();
      } catch (error: any) {
        onErrorRef.current(error.response?.data?.error || error.message || "Failed to complete rental request");
      }
    })();
  }, []);

  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 (!clientSecret) {
    return (
      <div className="text-center py-4">
        <p className="text-muted">Unable to load checkout</p>
      </div>
    );
  }

  return (
    <div id="embedded-checkout">
      <EmbeddedCheckoutProvider
        key={clientSecret} // Force remount if clientSecret changes
        stripe={stripePromise}
        options={{
          clientSecret,
          onComplete: handleComplete
        }}
      >
        <EmbeddedCheckout />
      </EmbeddedCheckoutProvider>
    </div>
  );
};

export default EmbeddedStripeCheckout;