/**
 * Product filter chip — autocomplete search for specific products.
 *
 * @package RawTypeOE
 */

import { useCallback, useEffect, useRef, useState } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import { Badge, EmptyState, Label, Notice, Skeleton, TextField } from '@rawtype/ui';
import apiFetch from '../utils/apiFetch';

export default function ProductFilterChip( { filter, onChange } ) {
	const [ query, setQuery ] = useState( '' );
	const [ results, setResults ] = useState( [] );
	const [ loading, setLoading ] = useState( false );
	const [ error, setError ] = useState( null );
	const debounceRef = useRef( null );
	const searchAbortRef = useRef( null );

	const selectedProducts = Array.isArray( filter.selectedProducts )
		? filter.selectedProducts
		: [];
	const selectedIds = Array.isArray( filter.value ) ? filter.value : [];

	useEffect( () => {
		if ( query.length < 3 ) {
			setResults( [] );
			return;
		}

		if ( debounceRef.current ) {
			clearTimeout( debounceRef.current );
		}

		debounceRef.current = setTimeout( () => {
			// Abort the previous in-flight search so a slow earlier response
			// cannot overwrite the results of the latest keystroke.
			if ( searchAbortRef.current ) {
				searchAbortRef.current.abort();
			}
			const controller = new AbortController();
			searchAbortRef.current = controller;

			setLoading( true );
			setError( null );

			apiFetch( {
				path: '/rawtype_oe/v1/search/products?q=' + encodeURIComponent( query ),
				signal: controller.signal,
			} )
				.then( ( data ) => {
					setResults( Array.isArray( data ) ? data : [] );
					setLoading( false );
				} )
				.catch( ( err ) => {
					if ( 'AbortError' !== err.name ) {
						setError( err );
						setLoading( false );
					}
				} );
		}, 300 );

		return () => {
			if ( debounceRef.current ) {
				clearTimeout( debounceRef.current );
			}
			if ( searchAbortRef.current ) {
				searchAbortRef.current.abort();
			}
		};
	}, [ query ] );

	const handleSelect = useCallback(
		( product ) => {
			if ( selectedIds.includes( product.id ) ) {
				return;
			}

			const newIds = [ ...selectedIds, product.id ];
			const newProducts = [ ...selectedProducts, product ];

			onChange( {
				...filter,
				value: newIds,
				selectedProducts: newProducts,
			} );
			setQuery( '' );
			setResults( [] );
		},
		[ filter, onChange, selectedIds, selectedProducts ],
	);

	const handleRemoveProduct = useCallback(
		( productId ) => {
			const newIds = selectedIds.filter( ( id ) => id !== productId );
			const newProducts = selectedProducts.filter( ( p ) => p.id !== productId );

			onChange( {
				...filter,
				value: newIds,
				selectedProducts: newProducts,
			} );
		},
		[ filter, onChange, selectedIds, selectedProducts ],
	);

	return (
		<div className="roe-product-filter">
			<Label size="sm">
				{ __( 'Specific product', 'rawtype-order-exporter-woocommerce' ) }
			</Label>

			<div className="roe-product-search">
				<TextField
					placeholder={ __( 'Search by name or SKU (min. 3 characters)...', 'rawtype-order-exporter-woocommerce' ) }
					value={ query }
					onChange={ ( e ) => setQuery( e.target.value ) }
				/>

				{ loading && <Skeleton width="100%" height={ 36 } /> }

				{ error && (
					<Notice type="error">
						{ __( 'Search error', 'rawtype-order-exporter-woocommerce' ) }
					</Notice>
				) }

				{ results.length > 0 && (
					<div className="roe-product-results">
						{ results.map( ( product ) => {
							const isSelected = selectedIds.includes( product.id );
							return (
								<button
									key={ product.id }
									type="button"
									className={
										'roe-product-result' +
										( isSelected ? ' roe-product-result--selected' : '' )
									}
									disabled={ isSelected }
									onClick={ () => handleSelect( product ) }
								>
									<span className="roe-product-result-name">
										{ product.name }
									</span>
									{ product.sku && (
										<span className="roe-product-result-sku">
											{ sprintf(
												/* translators: %s: product SKU */
												__( 'SKU: %s', 'rawtype-order-exporter-woocommerce' ),
												product.sku,
											) }
										</span>
									) }
									{ product.price && (
										<span className="roe-product-result-price">
											{ product.price }
										</span>
									) }
								</button>
							);
						} ) }
					</div>
				) }

				{ query.length >= 3 && ! loading && 0 === results.length && ! error && (
					<EmptyState
						title={ __( 'No results', 'rawtype-order-exporter-woocommerce' ) }
						description={ __( 'No matching products found', 'rawtype-order-exporter-woocommerce' ) }
					/>
				) }
			</div>

			{ selectedProducts.length > 0 && (
				<div className="roe-product-selected">
					{ selectedProducts.map( ( product ) => (
						<Badge key={ product.id } variant="default">
							{ product.name }
							{ product.sku ? ' (' + product.sku + ')' : '' }
							<button
								type="button"
								className="roe-product-selected-remove"
								onClick={ () => handleRemoveProduct( product.id ) }
								aria-label={ sprintf(
									/* translators: %s: product name */
									__( 'Remove %s', 'rawtype-order-exporter-woocommerce' ),
									product.name,
								) }
							>
								×
							</button>
						</Badge>
					) ) }
				</div>
			) }
		</div>
	);
}

/**
 * Get a human-readable summary of a product filter.
 *
 * @param {Object} filter The product filter object.
 * @return {string} Summary text.
 */
export function getProductFilterSummary( filter ) {
	const products = Array.isArray( filter.selectedProducts )
		? filter.selectedProducts
		: [];
	if ( 0 === products.length ) {
		return '...';
	}
	if ( products.length > 2 ) {
		return products[ 0 ].name + ' (+' + ( products.length - 1 ) + ')';
	}
	return products.map( ( p ) => p.name ).join( ', ' );
}
