import React, {
  createContext,
  useContext,
  useState,
  useCallback,
  useEffect,
  ReactNode,
} from "react";
import { useLocation } from "react-router-dom";
import { useTranslation } from "react-i18next";
import licenseService from "@app/services/licenseService";
import UpdateSeatsModal from "@app/components/shared/UpdateSeatsModal";
import { userManagementService } from "@app/services/userManagementService";
import { alert } from "@app/components/toast";
import { useOptionalLicense } from "@app/contexts/LicenseContext";
import { resyncExistingLicense } from "@app/utils/licenseCheckoutUtils";

export interface UpdateSeatsOptions {
  onSuccess?: () => void;
  onError?: (error: string) => void;
}

interface UpdateSeatsContextValue {
  openUpdateSeats: (options?: UpdateSeatsOptions) => Promise<void>;
  closeUpdateSeats: () => void;
  isOpen: boolean;
  isLoading: boolean;
}

const UpdateSeatsContext = createContext<UpdateSeatsContextValue | undefined>(
  undefined,
);

interface UpdateSeatsProviderProps {
  children: ReactNode;
}

export const UpdateSeatsProvider: React.FC<UpdateSeatsProviderProps> = ({
  children,
}) => {
  const { t } = useTranslation();
  const location = useLocation();
  // Use optional hook - won't throw during setup wizard when license provider isn't needed
  const license = useOptionalLicense();
  const [isOpen, setIsOpen] = useState(false);
  const [isLoading, setIsLoading] = useState(false);
  const [currentSeats, setCurrentSeats] = useState<number>(1);
  const [minimumSeats, setMinimumSeats] = useState<number>(1);
  const [currentOptions, setCurrentOptions] = useState<UpdateSeatsOptions>({});

  // Handle return from Stripe billing portal
  useEffect(() => {
    // CRITICAL FIX: Don't run billing check on auth routes to prevent race conditions
    // during SAML/OAuth callback. This check only matters after successful billing
    // portal redirects, which never happen on auth routes.
    const isAuthRoute =
      location.pathname === "/login" ||
      location.pathname === "/signup" ||
      location.pathname === "/auth/callback" ||
      location.pathname.startsWith("/invite/");

    if (isAuthRoute) {
      console.log(
        "[UpdateSeatsContext] On auth route, skipping billing return check",
      );
      return;
    }

    const handleBillingReturn = async () => {
      const urlParams = new URLSearchParams(window.location.search);
      const seatsUpdated = urlParams.get("seats_updated");

      if (seatsUpdated === "true") {
        console.log("Seats updated successfully, syncing license with Keygen");

        // Clear URL parameters
        window.history.replaceState({}, "", window.location.pathname);

        try {
          // Wait a moment for Stripe webhook to process
          await new Promise((resolve) => setTimeout(resolve, 2000));

          // Resync license with Keygen (not just local fetch)
          console.log("Seat update detected - resyncing license with Keygen");
          const activation = await resyncExistingLicense();

          if (activation.success) {
            console.log("License synced successfully after seat update");

            // Refresh global license context
            await license?.refetchLicense();

            // Get updated license info for notification
            const updatedLicense = await licenseService.getLicenseInfo();

            alert({
              alertType: "success",
              title: t("billing.seatsUpdated", "Seats Updated"),
              body: t(
                "billing.seatsUpdatedMessage",
                "Your enterprise seats have been updated to {{seats}}",
                {
                  seats: updatedLicense.maxUsers,
                },
              ),
            });
          } else {
            throw new Error(activation.error || "Failed to sync license");
          }
        } catch (error) {
          console.error("Failed to sync license after seat update:", error);
          alert({
            alertType: "warning",
            title: t("billing.updateProcessing", "Update Processing"),
            body: t(
              "billing.updateProcessingMessage",
              "Your seat update is being processed. Please refresh in a few moments.",
            ),
          });
        }
      }
    };

    // CRITICAL FIX: Properly handle async function and catch errors
    handleBillingReturn().catch((error) => {
      console.error(
        "[UpdateSeatsContext] Error in billing return handler:",
        error,
      );
      // Don't throw - this is initialization, should not block rendering
    });
  }, [t, location.pathname, license]);

  const openUpdateSeats = useCallback(
    async (options: UpdateSeatsOptions = {}) => {
      try {
        setIsLoading(true);

        // Fetch current license info and user count
        const [licenseInfo, userData] = await Promise.all([
          licenseService.getLicenseInfo(),
          userManagementService.getUsers(),
        ]);

        // Validate this is an enterprise license
        if (!licenseInfo || licenseInfo.licenseType !== "ENTERPRISE") {
          throw new Error(
            t(
              "billing.notEnterprise",
              "Seat management is only available for enterprise licenses",
            ),
          );
        }

        const currentLicenseSeats = licenseInfo.maxUsers || 1;
        const currentUserCount = userData.totalUsers || 0;

        // Minimum seats must be at least the current number of users
        const calculatedMinSeats = Math.max(currentUserCount, 1);

        console.log(
          `Opening seat update: current seats=${currentLicenseSeats}, current users=${currentUserCount}, minimum=${calculatedMinSeats}`,
        );

        setCurrentSeats(currentLicenseSeats);
        setMinimumSeats(calculatedMinSeats);
        setCurrentOptions(options);
        setIsOpen(true);
      } catch (err) {
        const errorMessage =
          err instanceof Error ? err.message : "Failed to open seat update";
        console.error("Error opening seat update:", errorMessage);
        alert({
          alertType: "error",
          title: t("common.error", "Error"),
          body: errorMessage,
        });
        options.onError?.(errorMessage);
      } finally {
        setIsLoading(false);
      }
    },
    [t],
  );

  const closeUpdateSeats = useCallback(() => {
    setIsOpen(false);
    setCurrentOptions({});

    // Refetch license after modal closes to update UI
    license?.refetchLicense();
  }, [license]);

  const handleUpdateSeats = useCallback(
    async (newSeatCount: number): Promise<string> => {
      try {
        // Get current license key
        const licenseInfo = await licenseService.getLicenseInfo();
        if (!licenseInfo?.licenseKey) {
          throw new Error("No license key found");
        }

        console.log(`Updating seats from ${currentSeats} to ${newSeatCount}`);

        // Call manage-billing function with new seat count
        const portalUrl = await licenseService.updateEnterpriseSeats(
          newSeatCount,
          licenseInfo.licenseKey,
        );

        return portalUrl;
      } catch (err) {
        const errorMessage =
          err instanceof Error ? err.message : "Failed to update seats";
        console.error("Error updating seats:", errorMessage);
        currentOptions.onError?.(errorMessage);
        throw err;
      }
    },
    [currentSeats, currentOptions],
  );

  const handleSuccess = useCallback(() => {
    console.log("Seat update initiated successfully");
    currentOptions.onSuccess?.();
  }, [currentOptions]);

  const handleError = useCallback(
    (error: string) => {
      console.error("Seat update error:", error);
      currentOptions.onError?.(error);
    },
    [currentOptions],
  );

  return (
    <UpdateSeatsContext.Provider
      value={{
        openUpdateSeats,
        closeUpdateSeats,
        isOpen,
        isLoading,
      }}
    >
      {children}
      <UpdateSeatsModal
        opened={isOpen}
        onClose={closeUpdateSeats}
        currentSeats={currentSeats}
        minimumSeats={minimumSeats}
        _onSuccess={handleSuccess}
        onError={handleError}
        onUpdateSeats={handleUpdateSeats}
      />
    </UpdateSeatsContext.Provider>
  );
};

export const useUpdateSeats = (): UpdateSeatsContextValue => {
  const context = useContext(UpdateSeatsContext);
  if (!context) {
    throw new Error(
      "useUpdateSeats must be used within an UpdateSeatsProvider",
    );
  }
  return context;
};

export default UpdateSeatsContext;
