import { useEffect, useMemo, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { Spinner, TextControl, Button } from '@wordpress/components';
import { Search } from 'lucide-react';
import apiFetch from '@wordpress/api-fetch';
import ColorControl from '@cliqui/admin/src/components/builder/ColorControl';

// Shared by every admin bundle that renders an icon picker.
const adminNamespace = () =>
	( typeof window !== 'undefined' &&
		window.CLIQTHEMES_UI?.app?.adminNamespace ) ||
	'cliqthemes-ui/v1';

const svgToDataUri = ( svg ) => 'data:image/svg+xml,' + encodeURIComponent( svg );

/** Compose a flat, colourable icon (no pin) from a glyph. */
const composeIcon = ( glyph, color ) =>
	`<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" data-cliq-widget-icon='${ glyph.slug }|${ color }'>` +
	`<g color="${ color }">${ glyph.glyph }</g>` +
	'</svg>';

/** Recover { slug, color } from a previously-saved icon value. */
const parse = ( value ) => {
	if ( typeof value !== 'string' || ! value.startsWith( 'data:image/svg+xml' ) ) {
		return null;
	}
	try {
		const svg = decodeURIComponent( value.slice( value.indexOf( ',' ) + 1 ) );
		const m = svg.match( /data-cliq-widget-icon='([^|]+)\|([^']+)'/ );
		return m ? { slug: m[ 1 ], color: m[ 2 ] } : null;
	} catch ( e ) {
		return null;
	}
};

const IconPickerField = ( { field, value, onChange } ) => {
	const saved = useMemo( () => parse( value ), [ value ] );

	const [ glyphs, setGlyphs ] = useState( null );
	const [ slug, setSlug ] = useState( saved?.slug ?? '' );
	const [ color, setColor ] = useState( saved?.color ?? '#3858e9' );
	const [ search, setSearch ] = useState( '' );
	// The icon grid is heavy (100+ recoloured SVGs) — keep it OUT of the DOM
	// until the user chooses to pick/change, so the form stays light. Open by
	// default only when there's no icon yet.
	const [ pickerOpen, setPickerOpen ] = useState( () => ! ( saved?.slug ) );

	useEffect( () => {
		let active = true;
		apiFetch( { path: `${ adminNamespace() }/admin/markers/assets` } )
			.then( ( res ) => active && setGlyphs( res?.glyphs ?? [] ) )
			.catch( () => active && setGlyphs( [] ) );
		return () => {
			active = false;
		};
	}, [] );

	const selected = useMemo(
		() => ( glyphs || [] ).find( ( g ) => g.slug === slug ) || null,
		[ glyphs, slug ]
	);

	const filtered = useMemo( () => {
		const q = search.trim().toLowerCase();
		const list = glyphs || [];
		return q
			? list.filter( ( g ) => g.name.toLowerCase().includes( q ) || g.slug.toLowerCase().includes( q ) )
			: list;
	}, [ glyphs, search ] );

	// Thumbnails reuse the chosen colour but are memoised on colour+filter only,
	// and only built while the picker is open (otherwise ~100 SVGs sit unused).
	const items = useMemo(
		() => ( pickerOpen ? filtered.map( ( g ) => ( { slug: g.slug, name: g.name, src: svgToDataUri( composeIcon( g, color ) ) } ) ) : [] ),
		[ filtered, color, pickerOpen ]
	);

	const currentSrc = useMemo(
		() => ( selected ? svgToDataUri( composeIcon( selected, color ) ) : '' ),
		[ selected, color ]
	);

	useEffect( () => {
		if ( selected && typeof onChange === 'function' ) {
			onChange( svgToDataUri( composeIcon( selected, color ) ) );
		}
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [ slug, color, selected ] );

	if ( glyphs === null ) {
		return (
			<div className="cliqthemes-ui-loading">
				<Spinner />
				<span>{ __( 'Loading icons…', 'cliq-store-locator' ) }</span>
			</div>
		);
	}

	return (
		<div className="cliqthemes-ui-icon-picker">
			{ field?.label && (
				<span className="components-base-control__label">{ field.label }</span>
			) }
			<div className="cliqthemes-ui-icon-picker__summary">
				<span className="cliqthemes-ui-icon-picker__current">
					{ currentSrc ? (
						<img src={ currentSrc } alt="" height={ 30 } />
					) : (
						<span className="cliqthemes-ui-muted">{ __( 'No icon selected', 'cliq-store-locator' ) }</span>
					) }
				</span>
				<Button variant="secondary" onClick={ () => setPickerOpen( ( o ) => ! o ) }>
					{ pickerOpen
						? __( 'Done', 'cliq-store-locator' )
						: selected
							? __( 'Change icon', 'cliq-store-locator' )
							: __( 'Choose icon', 'cliq-store-locator' ) }
				</Button>
			</div>

			{ pickerOpen && (
				<>
					<div className="cliqthemes-ui-icon-picker__bar">
						<ColorControl label={ __( 'Color', 'cliq-store-locator' ) } value={ color } onChange={ ( v ) => setColor( v || '#3858e9' ) } />
						<div className="cliqthemes-ui-marker-editor__search cliqthemes-ui-icon-picker__search">
							<Search size={ 15 } className="cliqthemes-ui-marker-editor__search-icon" />
							<TextControl
								__nextHasNoMarginBottom
								value={ search }
								onChange={ setSearch }
								placeholder={ __( 'Search icons — travel, food, auto…', 'cliq-store-locator' ) }
							/>
						</div>
					</div>
					<div className="cliqthemes-ui-marker-editor__grid cliqthemes-ui-icon-picker__grid">
						{ items.map( ( g ) => (
							<button
								type="button"
								key={ g.slug }
								data-title={ g.name }
								className={ `cliqthemes-ui-marker-editor__swatch${ g.slug === slug ? ' is-active' : '' }` }
								onClick={ () => setSlug( g.slug ) }
							>
								<img src={ g.src } alt={ g.name } height={ 24 } loading="lazy" />
							</button>
						) ) }
						{ items.length === 0 && (
							<p className="cliqthemes-ui-muted">{ __( 'No icons match your search.', 'cliq-store-locator' ) }</p>
						) }
					</div>
				</>
			) }
			{ field?.help && <p className="cliqthemes-ui-field-help">{ field.help }</p> }
		</div>
	);
};

export default IconPickerField;
