/**
 * FeatureCombobox — a single-value, REST-backed combobox for plan features.
 *
 * The Gutenberg equivalent of the Elementor single `arraysubs_feature` AJAX
 * select. The stored value is the feature NAME (a string key the gate matches),
 * not a numeric id. ComboboxControl is single-select; we feed it suggestions
 * from the select-options endpoint (type=features) and preload the saved value's
 * label via `include`.
 */
import { useState, useEffect, useRef, useMemo } from '@wordpress/element';
import { ComboboxControl } from '@wordpress/components';
import apiFetch from '@wordpress/api-fetch';
import { addQueryArgs } from '@wordpress/url';

const ROUTE =
	( window.ArraySubsGutenberg && window.ArraySubsGutenberg.restPath ) ||
	'/arraysubs/v1/members-access/select-options';

function rowsOf( response ) {
	return ( response && ( response.data || response.options ) ) || [];
}

export default function FeatureCombobox( { label, help, value, onChange } ) {
	// Feature value == feature label (the REST endpoint returns value === label),
	// but we still keep a set of known options so the current value shows up.
	const [ options, setOptions ] = useState( [] );
	const debounce = useRef();

	const merge = ( rows ) =>
		setOptions( ( prev ) => {
			const seen = {};
			const out = [];
			[ ...prev, ...rows.map( ( r ) => ( { value: String( r.value ), label: r.label } ) ) ].forEach(
				( opt ) => {
					if ( ! seen[ opt.value ] ) {
						seen[ opt.value ] = true;
						out.push( opt );
					}
				}
			);
			return out;
		} );

	// Populate the dropdown on open. The features endpoint ignores `include` and
	// returns the (small) full list, so an unfiltered fetch is the right call;
	// the saved value is guaranteed selectable by the allOptions fallback below.
	useEffect( () => {
		apiFetch( {
			path: addQueryArgs( ROUTE, { type: 'features', search: '' } ),
		} )
			.then( ( res ) => merge( rowsOf( res ) ) )
			.catch( () => {} );
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [] );

	const onFilterValueChange = ( term ) => {
		clearTimeout( debounce.current );
		debounce.current = setTimeout( () => {
			apiFetch( {
				path: addQueryArgs( ROUTE, { type: 'features', search: term || '' } ),
			} )
				.then( ( res ) => merge( rowsOf( res ) ) )
				.catch( () => {} );
		}, 300 );
	};

	// Guarantee the current value is always selectable.
	const allOptions = useMemo( () => {
		if ( value && ! options.some( ( o ) => o.value === String( value ) ) ) {
			return [ { value: String( value ), label: String( value ) }, ...options ];
		}
		return options;
	}, [ value, options ] );

	return (
		<ComboboxControl
			__next40pxDefaultSize
			__nextHasNoMarginBottom
			label={ label }
			help={ help }
			value={ value || null }
			options={ allOptions }
			onFilterValueChange={ onFilterValueChange }
			onChange={ ( v ) => onChange( v || '' ) }
			allowReset
		/>
	);
}
