import { useState, useEffect } from 'react';

// Define types for the options
interface ScopeOption {
	value: string;
	label: string;
}

interface ScopeOptionsState {
	loading: boolean;
	error: string | null;
	options: ScopeOption[];
}

// Cache to store options by field ID and form ID
const optionsCache: Record<string, ScopeOption[]> = {};

// Track in-flight requests to prevent duplicates
const inFlightRequests: Record<string, Promise<ScopeOption[]>> = {};

/**
 * Generate a cache key from form ID and field ID
 *
 * @param formId
 * @param fieldId
 */
const getCacheKey = (formId: string, fieldId: string): string => {
	return `${formId}_${fieldId}`;
};

/**
 * Make the actual AJAX request and return a promise
 *
 * @param fieldId The ID of the scope field
 * @param formId  The ID of the form
 * @return Promise that resolves with the options
 */
const fetchScopeOptions = (
	fieldId: string,
	formId: string
): Promise<ScopeOption[]> => {
	return new Promise((resolve, reject) => {
		jQuery
			.ajax({
				url: window.ajaxurl,
				method: 'POST',
				data: {
					action: 'gpi_get_scope_field_options',
					security: window.gpi_inventory_page_strings.nonce,
					fieldId,
					formId,
				},
			})
			.done((response) => {
				// Store in cache
				const cacheKey = getCacheKey(formId, fieldId);
				optionsCache[cacheKey] = response;

				// Resolve the promise
				resolve(response);
			})
			.fail((error) => {
				reject(error.responseText || 'Failed to fetch options');
			});
	});
};

/**
 * Get an existing in-flight request or create a new one
 *
 * @param cacheKey
 * @param fieldId
 * @param formId
 */
const getOrCreateRequest = (
	cacheKey: string,
	fieldId: string,
	formId: string
): Promise<ScopeOption[]> => {
	if (!inFlightRequests[cacheKey]) {
		inFlightRequests[cacheKey] = fetchScopeOptions(fieldId, formId);
	}
	return inFlightRequests[cacheKey];
};

/**
 * Hook to fetch and cache options for a scope field
 *
 * @param fieldId The ID of the scope field
 * @param formId  The ID of the form
 * @return Object with loading state, error, and options
 */
export function useScopeOptions(
	fieldId: string,
	formId: string
): ScopeOptionsState {
	const [state, setState] = useState<ScopeOptionsState>({
		loading: false,
		error: null,
		options: [],
	});

	useEffect(() => {
		// Skip if fieldId or formId is empty
		if (!fieldId || !formId) {
			return;
		}

		const cacheKey = getCacheKey(formId, fieldId);

		// Return cached options if available
		if (optionsCache[cacheKey]) {
			setState({
				loading: false,
				error: null,
				options: optionsCache[cacheKey],
			});
			return;
		}

		// Set loading state
		setState((prev) => ({ ...prev, loading: true }));

		// Use setTimeout to defer the request check/creation
		// This helps prevent race conditions when multiple components mount simultaneously
		const timeoutId = setTimeout(() => {
			// Get or create the request
			const requestPromise = getOrCreateRequest(
				cacheKey,
				fieldId,
				formId
			);

			requestPromise
				.then((options) => {
					setState({
						loading: false,
						error: null,
						options,
					});

					// Clean up the in-flight request
					delete inFlightRequests[cacheKey];
				})
				.catch((error) => {
					setState({
						loading: false,
						error,
						options: [],
					});

					// Clean up the in-flight request
					delete inFlightRequests[cacheKey];
				});
		}, 0);

		// Clean up the timeout if the component unmounts
		return () => clearTimeout(timeoutId);
	}, [fieldId, formId]);

	return state;
}
