import { StateCreator } from 'zustand';
import { getAdvancedInventoryFieldResource } from '../../utils/fieldUtils';

const strings = window.gpi_inventory_page_strings;

/**
 * Interface for inventory data
 */
interface InventoryData {
	inventory: number | null;
	isLoading: boolean;
	error: string | null;
}

/**
 * Interface for choice inventory data
 */
interface ChoiceInventoryData {
	[choiceValue: string]: number;
}

interface ChoiceInventoriesState {
	[fieldId: number]: {
		choices: ChoiceInventoryData;
		isLoading: boolean;
		error: string | null;
	};
}

/**
 * Interface for scoped inventory data
 */
interface ScopedInventoryData {
	inventory: number | null;
	isLoading: boolean;
	error: string | null;
}

/**
 * Interface for scoped choice inventory data
 */
interface ScopedChoiceInventoriesState {
	[key: string]: {
		choices: ChoiceInventoryData;
		isLoading: boolean;
		error: string | null;
	};
}

/**
 * Helper function to generate a unique key for scoped inventory
 *
 * @param fieldId
 * @param scopeValues
 */
export const getScopedInventoryKey = (
	fieldId: number,
	scopeValues: Record<string, string>
): string => {
	return `${fieldId}_${JSON.stringify(scopeValues)}`;
};

export interface InventoriesSlice {
	// State
	inventories: Record<number, InventoryData>;
	choiceInventories: ChoiceInventoriesState;
	scopedInventories: Record<string, ScopedInventoryData>;
	scopedChoiceInventories: ScopedChoiceInventoriesState;

	// Actions
	fetchInventory: (fieldId: number) => Promise<void>;
	fetchChoiceInventory: (fieldId: number) => Promise<void>;
	fetchScopedInventory: (
		fieldId: number,
		scopeValues: Record<string, string>
	) => Promise<void>;
	fetchScopedChoiceInventory: (
		fieldId: number,
		scopeValues: Record<string, string>
	) => Promise<void>;

	// Selectors
	getScopedChoiceInventoryData: (
		fieldId: number,
		scopeValues: Record<string, string>
	) => {
		choices: ChoiceInventoryData;
		isLoading: boolean;
		error: string | null;
	};
}

export const createInventoriesSlice: StateCreator<
	InventoriesSlice,
	[],
	[],
	InventoriesSlice
> = (set, get) => ({
	// Initial state
	inventories: {},
	choiceInventories: {},
	scopedInventories: {},
	scopedChoiceInventories: {},

	// Actions
	fetchInventory: async (fieldId) => {
		// Set loading state for this field
		set((state) => ({
			inventories: {
				...state.inventories,
				[fieldId]: {
					inventory: state.inventories[fieldId]?.inventory ?? null,
					isLoading: true,
					error: null,
				},
			},
		}));

		try {
			// Get the form ID from the global window object
			const formId = window.form.id;

			// Make AJAX request to get claimed inventory
			const response = await jQuery.ajax({
				url: window.ajaxurl,
				method: 'POST',
				data: {
					action: 'gpi_get_simple_current_inventory_claimed',
					security: strings.nonce,
					fieldId,
					formId,
				},
			});

			// Get the field to determine the inventory limit
			const field = window.form.fields.find((f) => f.id === fieldId);
			const limit = field?.gpiInventoryLimit || 0;

			// Calculate available inventory
			// The response might be a JSON string or already parsed
			const claimed =
				typeof response === 'string' ? parseInt(response) : response;
			const available = Math.max(0, limit - (claimed || 0));

			// Update store with real data
			set((state) => ({
				inventories: {
					...state.inventories,
					[fieldId]: {
						inventory: available,
						isLoading: false,
						error: null,
					},
				},
			}));
		} catch (error) {
			// Set error state
			set((state) => ({
				inventories: {
					...state.inventories,
					[fieldId]: {
						inventory:
							state.inventories[fieldId]?.inventory ?? null,
						isLoading: false,
						error:
							error instanceof Error
								? error.message
								: 'Failed to fetch inventory',
					},
				},
			}));
		}
	},

	// New action to fetch choice inventory data
	fetchChoiceInventory: async (fieldId) => {
		// Set loading state for this field's choices
		set((state) => ({
			choiceInventories: {
				...state.choiceInventories,
				[fieldId]: {
					choices: state.choiceInventories[fieldId]?.choices || {},
					isLoading: true,
					error: null,
				},
			},
		}));

		try {
			// Get the form ID from the global window object
			const formId = window.form.id;

			// Make AJAX request to get claimed inventory for choices
			const response = await jQuery.ajax({
				url: window.ajaxurl,
				method: 'POST',
				data: {
					action: 'gpi_get_choices_current_inventory_claimed',
					security: strings.nonce,
					fieldId,
					formId,
				},
			});

			// Get the field to determine choice limits
			const field = window.form.fields.find((f) => f.id === fieldId);

			// Process response to calculate available inventory for each choice
			const choiceInventory: ChoiceInventoryData = {};

			if (field && field.choices) {
				field.choices.forEach(
					(choice: { value: string; inventory_limit?: string }) => {
						const limit = choice.inventory_limit
							? parseInt(choice.inventory_limit)
							: 0;
						const claimed = response[choice.value] || 0;
						choiceInventory[choice.value] = Math.max(
							0,
							limit - claimed
						);
					}
				);
			}

			// Update store with real data
			set((state) => ({
				choiceInventories: {
					...state.choiceInventories,
					[fieldId]: {
						choices: choiceInventory,
						isLoading: false,
						error: null,
					},
				},
			}));
		} catch (error) {
			// Set error state
			set((state) => ({
				choiceInventories: {
					...state.choiceInventories,
					[fieldId]: {
						choices:
							state.choiceInventories[fieldId]?.choices || {},
						isLoading: false,
						error:
							error instanceof Error
								? error.message
								: 'Failed to fetch choice inventory',
					},
				},
			}));
		}
	},

	// New action for fetching scoped inventory
	fetchScopedInventory: async (fieldId, scopeValues) => {
		const key = getScopedInventoryKey(fieldId, scopeValues);

		// Set loading state
		set((state) => ({
			scopedInventories: {
				...state.scopedInventories,
				[key]: {
					inventory: state.scopedInventories[key]?.inventory ?? null,
					isLoading: true,
					error: null,
				},
			},
		}));

		try {
			// Get the form ID from the global window object
			const formId = window.form.id;

			// Make AJAX request to get claimed inventory with scopes
			const response = await jQuery.ajax({
				url: window.ajaxurl,
				method: 'POST',
				data: {
					action: 'gpi_get_scoped_inventory',
					security: strings.nonce,
					fieldId,
					formId,
					scopeValues,
				},
			});

			// Get the field to determine the inventory limit
			const field = window.form.fields.find((f) => f.id === fieldId);
			if (!field) {
				throw new Error('Field not found');
			}

			// const limit = field?.gpiInventoryLimit || 0;
			const resource = getAdvancedInventoryFieldResource(field);
			const limit = resource?.inventory_limit || 0;

			// Calculate available inventory
			const claimed =
				typeof response === 'string' ? parseInt(response) : response;
			const available = Math.max(0, limit - (claimed || 0));

			// Update store with real data
			set((state) => ({
				scopedInventories: {
					...state.scopedInventories,
					[key]: {
						inventory: available,
						isLoading: false,
						error: null,
					},
				},
			}));
		} catch (error) {
			// Set error state
			set((state) => ({
				scopedInventories: {
					...state.scopedInventories,
					[key]: {
						inventory:
							state.scopedInventories[key]?.inventory ?? null,
						isLoading: false,
						error:
							error instanceof Error
								? error.message
								: 'Failed to fetch scoped inventory',
					},
				},
			}));
		}
	},

	// Action for fetching scoped choice inventory
	fetchScopedChoiceInventory: async (fieldId, scopeValues) => {
		const key = getScopedInventoryKey(fieldId, scopeValues);

		// Set loading state
		set((state) => ({
			scopedChoiceInventories: {
				...state.scopedChoiceInventories,
				[key]: {
					choices: state.scopedChoiceInventories[key]?.choices || {},
					isLoading: true,
					error: null,
				},
			},
		}));

		try {
			// Get the form ID from the global window object
			const formId = window.form.id;

			// Make AJAX request to get claimed inventory with scopes
			const response = await jQuery.ajax({
				url: window.ajaxurl,
				method: 'POST',
				data: {
					action: 'gpi_get_scoped_choice_inventory',
					security: strings.nonce,
					fieldId,
					formId,
					scopeValues,
				},
			});

			// Update store with real data
			set((state) => ({
				scopedChoiceInventories: {
					...state.scopedChoiceInventories,
					[key]: {
						choices: response || {},
						isLoading: false,
						error: null,
					},
				},
			}));
		} catch (error) {
			// Set error state
			set((state) => ({
				scopedChoiceInventories: {
					...state.scopedChoiceInventories,
					[key]: {
						choices:
							state.scopedChoiceInventories[key]?.choices || {},
						isLoading: false,
						error:
							error instanceof Error
								? error.message
								: 'Failed to fetch scoped choice inventory',
					},
				},
			}));
		}
	},

	// Selector for getting scoped choice inventory data
	getScopedChoiceInventoryData: (fieldId, scopeValues) => {
		const state = get();
		const key = getScopedInventoryKey(fieldId, scopeValues);

		return (
			state.scopedChoiceInventories[key] || {
				choices: {},
				isLoading: false,
				error: null,
			}
		);
	},
});
