import {useState, useRef, useEffect, useMemo} from '@wordpress/element';
import {__} from '@wordpress/i18n';
import './TokenSelect.scss';
import {Popover} from '@wordpress/components';

const TokenSelect = ( {
						  options,
						  selectedOptions, // Expects array when multi, but single object or null when single
						  onChange,
						  onSearch,
						  placeholder,
						  isLoading,
						  isSingle = false,
						  className = '',
						  tokenClassName = '',
						  disabled = false,
					  } ) => {
	const [isOpen, setIsOpen] = useState( false );
	const [query, setQuery] = useState( '' );
	const containerRef = useRef( null );
	const inputRef = useRef( null );

	// Normalise selectedOptions to an array for internal workflow
	const selection = useMemo( () => {
		if ( !selectedOptions ) {
			return [];
		}
		return Array.isArray( selectedOptions ) ? selectedOptions : [selectedOptions];
	}, [selectedOptions] );

	// Helper: get the class of a group for a specific value
	const getGroupClass = ( optionValue ) => {
		const isGrouped = options.length > 0 && options[0].options;
		if ( !isGrouped ) return '';

		for ( const group of options ) {
			if ( group.options.some( opt => opt.value === optionValue ) ) {
				return group.class || '';
			}
		}
		return '';
	};

	// Close when clicking outside.
	useEffect( () => {
		const handleClickOutside = ( event ) => {
			const popoverContent = document.querySelector( '.adpresso-token-select__popover-content' );

			if (
				containerRef.current &&
				!containerRef.current.contains( event.target ) &&
				(!popoverContent || !popoverContent.contains( event.target ))
			) {
				setIsOpen( false );
				setQuery( '' );
			}
		};
		document.addEventListener( 'mousedown', handleClickOutside );
		return () => document.removeEventListener( 'mousedown', handleClickOutside );
	}, [] );

	const handleRemoveOption = ( optionToRemove ) => {
		if ( isSingle ) {
			onChange( null );
		} else {
			onChange( selection.filter( opt => opt.value !== optionToRemove.value ) );
		}
		inputRef.current?.focus();
	};

	const handleSelectOption = ( optionToAdd ) => {
		if ( isSingle ) {
			onChange( [optionToAdd] );
			setIsOpen( false );
		} else {
			onChange( [...selection, optionToAdd] );
			setQuery( '' );
			onSearch && onSearch( '' );
			inputRef.current?.focus(); // Focus back for another input.
		}
	};

	// Filter logic supports flat lists and groups
	const filteredOptions = useMemo( () => {
		const q = query.toLowerCase();

		const isSelected = ( opt ) => selection.some( sel => sel.value === opt.value );
		const matchesQuery = ( opt ) => opt.label.toLowerCase().includes( q );

		const isGrouped = options.length > 0 && options[0].options;

		if ( isGrouped ) {
			return options.map( group => {
				const groupOptions = group.options.filter( opt =>
					!isSelected( opt ) && matchesQuery( opt )
				);
				return groupOptions.length > 0 ? {...group, options: groupOptions} : null;
			} ).filter( Boolean );
		} else {
			// Flat list
			return options.filter( opt => !isSelected( opt ) && matchesQuery( opt ) );
		}
	}, [options, selection, query] );

	return (
		<div className={`adpresso-token-select ${isSingle ? 'is-single' : 'is-multi'} ${isOpen ? 'is-open' : ''}`} ref={containerRef}>
			<div className={`adpresso-token-select__control ${className}`} onClick={() => inputRef.current?.focus()}>
				{selection.map( option => {
					const groupClass = getGroupClass( option.value );

					return (
						<span
							key={option.value}
							className={`adpresso-token-select__token ${tokenClassName} ${groupClass}`.trim()}
						>
                      {option.label}
							<button
								type="button"
								className="adpresso-token-select__remove"
								onClick={( e ) => {
									e.stopPropagation();
									handleRemoveOption( option );
								}}
							>&times;</button>
                   </span>
					);
				} )}

				<input
					ref={inputRef}
					type="text"
					className="adpresso-token-select__input"
					value={query}
					disabled={disabled}
					onChange={( e ) => {
						setQuery( e.target.value );
						onSearch && onSearch( e.target.value );
						setIsOpen( true );
					}}
					onFocus={() => setIsOpen( true )}
					placeholder={selection.length === 0 ? placeholder : ''}
				/>
			</div>

			{/* --- Dropdown Menu --- */}
			{isOpen && (
				<Popover
					anchor={containerRef.current}
					onClose={() => setIsOpen( false )}
					position="left center"
					noArrow={true}
					className="adpresso-token-select__popover"
					focusOnMount={false}
				>
					<div className="adpresso-token-select__popover-content">
						<ul className="adpresso-token-select__menu">
							{isLoading && <li className="is-loading">{__( 'Loading...', 'adpresso' )}</li>}

							{!isLoading && filteredOptions.length === 0 && (
								<li className="is-empty">{__( 'No results found.', 'adpresso' )}</li>
							)}

							{!isLoading && filteredOptions.map( ( item, index ) => {
								if ( item.options ) {
									return (
										<li key={index} className="adpresso-token-select__group">
											<div className={`adpresso-token-select__group-label ${item.class}`}>{item.label}</div>
											<ul className="adpresso-token-select__group-options">
												{item.options.map( opt => (
													<li
														key={opt.value}
														className="adpresso-token-select__option"
														onClick={() => handleSelectOption( { ...opt, groupClass: item.class } )}
													>
														{opt.label}
													</li>
												) )}
											</ul>
										</li>
									);
								}
								return (
									<li
										key={item.value}
										className="adpresso-token-select__option"
										onClick={() => handleSelectOption( item )}
									>
										{item.label}
									</li>
								);
							} )}
						</ul>
					</div>
				</Popover>
			)}
		</div>
	);
};

export default TokenSelect;
