import {useState, useEffect, useMemo} from '@wordpress/element';
import {Spinner} from '@wordpress/components';
import FieldControl from '../components/FieldControl';
import {useDebounce} from '@wordpress/compose';
import {addQueryArgs} from '@wordpress/url';
import TokenSelect from '../components/TokenSelect';

const {restUrl, apiNonce} = window.adpressoAdminData || {};

const TokenSelectField = ( {field, value, onChange, variantClass, tokenClassName} ) => {
	const isValueEmpty = value === undefined || value === null || value === '';
	const disabled = (field.premium || field.disabled) ?? false;

	useEffect( () => {
		if ( isValueEmpty && field.default !== undefined ) {
			onChange( field.id, field.default );
		}
	}, [isValueEmpty, field.default, field.id, onChange] );

	const currentSelectionIds = useMemo( () => {
		if ( value === null || value === undefined ) {
			return [];
		}
		return Array.isArray( value ) ? value : [value];
	}, [value] );

	// States for the data logic
	const [searchQuery, setSearchQuery] = useState( '' );
	const debouncedSearchQuery = useDebounce( searchQuery, 300 );
	const [availableOptions, setAvailableOptions] = useState( field.options || [] );
	const [isLoading, setIsLoading] = useState( false );

	// Load the dynamic options
	useEffect( () => {
		if ( !field.options_callback?.rest_endpoint ) {
			return;
		}

		const abortController = new AbortController();
		const fetchOptions = async () => {
			setIsLoading( true );
			const endpointPath = field.options_callback.rest_endpoint;
			const queryArgs = debouncedSearchQuery ? {search: debouncedSearchQuery} : {};
			const finalUrl = addQueryArgs( `${restUrl}${endpointPath}`, queryArgs );

			try {
				const options = await wp.apiFetch( {
					path:   finalUrl,
					signal: abortController.signal
				} );
				setAvailableOptions( options );
			} catch ( error ) {
				if ( error.name !== 'AbortError' ) {
					console.error( `Failed to fetch options from '${endpointPath}'.`, error );
				}
			} finally {
				setIsLoading( false );
			}
		};

		fetchOptions();
		return () => abortController.abort();
	}, [debouncedSearchQuery, field.options_callback] );

	const selectedOptions = useMemo( () => {
		return currentSelectionIds.map( id => {
			// Search in flat list
			let found = availableOptions.find( opt => opt.value == id );

			// Search in groups
			if ( !found ) {
				for ( const group of availableOptions ) {
					if ( group.options && Array.isArray( group.options ) ) {
						found = group.options.find( opt => opt.value == id );
						if ( found ) {
							break;
						}
					}
				}
			}
			return found;
		} ).filter( Boolean ); // Remove not found options
	}, [currentSelectionIds, availableOptions] );

	const handleSelectionChange = ( newSelectedOptions ) => {
		if ( !newSelectedOptions ) {
			onChange( field.id, field.isSingle ? '' : [] );
			return;
		}

		const newIds = newSelectedOptions.map( opt => opt.value );

		// For single select save the value, for multi the array
		const valueToSave = field.isSingle ? (newIds[0] || '') : newIds;

		onChange( field.id, valueToSave );
	};

	return (
		<TokenSelect
			options={availableOptions}
			selectedOptions={selectedOptions}
			onChange={handleSelectionChange}
			onSearch={setSearchQuery}
			placeholder={field.placeholder || 'Select...'}
			isLoading={isLoading}
			isSingle={field.isSingle}
			className={variantClass}
			tokenClassName={tokenClassName}
			disabled={disabled}
		/>
	);
};

export default TokenSelectField;
