/**
 * Searchable multi-library icon picker for in-block content icons (buttons, etc.).
 * Does not replace Gutenberg block-registration Dashicons IconPicker.
 */
import { Button, Popover, TextControl } from '@wordpress/components';
import { useEffect, useMemo, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import {
	ensureIconStylesheets,
	fetchInlineIconSvg,
	getCachedInlineIconSvg,
	getEnabledIconLibraries,
	iconClassNames,
	normalizeIconRef,
	parseIconRef,
	renderIconHtml,
} from '../../shared/iconRegistry';
const INLINE_PREVIEW_LIMIT = 96;

/**
 * Glyph for picker cells — class-based (FA/Dashicons), ligature (Material),
 * or on-demand svg-inline (Lucide).
 *
 * @param {object} props
 * @param {object|null} props.library
 * @param {string} props.iconId
 */
function IconGlyph( { library, iconId } ) {
	const ref =
		library?.id && iconId ? `${ library.id }:${ iconId }` : '';
	const [ inlineHtml, setInlineHtml ] = useState( () =>
		ref && library?.type === 'svg-inline'
			? getCachedInlineIconSvg( ref )
			: ''
	);

	useEffect( () => {
		if ( library?.type !== 'svg-inline' || ! library?.id || ! iconId ) {
			return undefined;
		}
		let cancelled = false;
		const key = `${ library.id }:${ iconId }`;
		const cached = getCachedInlineIconSvg( key );
		if ( cached ) {
			setInlineHtml( cached );
			return undefined;
		}
		fetchInlineIconSvg( library.id, iconId ).then( ( svg ) => {
			if ( ! cancelled ) {
				setInlineHtml( svg || '' );
			}
		} );
		return () => {
			cancelled = true;
		};
	}, [ library?.type, library?.id, iconId ] );

	const className = iconClassNames( library, iconId );
	const style = {
		fontSize: '18px',
		width: '1.15em',
		height: '1.15em',
		lineHeight: 1,
		display: 'inline-flex',
		alignItems: 'center',
		justifyContent: 'center',
	};

	if ( library?.type === 'svg-inline' ) {
		const sized =
			'width:18px;height:18px;display:block;flex-shrink:0';
		// Re-render from cache after fetch (inlineHtml is the re-render trigger).
		void inlineHtml;
		const html = renderIconHtml( ref, sized, '', [ library ] );
		return (
			<span
				className="bm-universal-icon-picker__glyph bm-universal-icon-picker__glyph--svg"
				style={ {
					display: 'inline-flex',
					width: 18,
					height: 18,
					alignItems: 'center',
					justifyContent: 'center',
					color: 'currentColor',
				} }
				dangerouslySetInnerHTML={ { __html: html } }
			/>
		);
	}

	if ( library?.type === 'svg-sprite' ) {
		const html = renderIconHtml(
			`${ library.id }:${ iconId }`,
			'font-size:18px;width:1em;height:1em',
			'',
			[ library ]
		);
		return (
			<span
				className="bm-universal-icon-picker__glyph"
				dangerouslySetInnerHTML={ { __html: html } }
			/>
		);
	}

	if ( library?.textContent ) {
		return (
			<span className={ className } style={ style } aria-hidden="true">
				{ iconId }
			</span>
		);
	}

	// Font Awesome / Dashicons: empty element — glyph comes from CSS :before.
	return (
		<span className={ className } style={ style } aria-hidden="true" />
	);
}

/**
 * @param {string} html
 * @param {object|null} [library]
 * @param {string} [iconId]
 */
function IconPreview( { html, library, iconId } ) {
	if ( ! html && ! iconId ) {
		return (
			<span
				className="dashicons dashicons-plus-alt2"
				aria-hidden="true"
			/>
		);
	}
	if (
		library &&
		iconId &&
		library.type !== 'svg-sprite' &&
		library.type !== 'svg-inline' &&
		library.type !== 'css-mask'
	) {
		return (
			<span className="bm-universal-icon-picker__preview">
				<IconGlyph library={ library } iconId={ iconId } />
			</span>
		);
	}
	if ( library?.type === 'svg-inline' && iconId ) {
		return (
			<span className="bm-universal-icon-picker__preview">
				<IconGlyph library={ library } iconId={ iconId } />
			</span>
		);
	}
	return (
		<span
			className="bm-universal-icon-picker__preview"
			dangerouslySetInnerHTML={ { __html: html } }
		/>
	);
}

/**
 * @param {object}   props
 * @param {string}   props.value
 * @param {Function} props.onChange
 * @param {string}   [props.label]
 */
export default function UniversalIconPicker( {
	value = '',
	onChange,
	label,
} ) {
	const [ open, setOpen ] = useState( false );
	const [ query, setQuery ] = useState( '' );
	const [ cssReady, setCssReady ] = useState( false );
	const libraries = useMemo( () => getEnabledIconLibraries(), [ open ] );
	const current = normalizeIconRef( value );
	const parsed = parseIconRef( current );
	const [ activeLib, setActiveLib ] = useState(
		() => parsed?.libraryId || libraries[ 0 ]?.id || 'dashicons'
	);

	useEffect( () => {
		if ( ! open ) {
			return undefined;
		}
		ensureIconStylesheets( libraries );
		// Re-apply after paint so FA @font-face can resolve; mark ready for layout.
		const t = window.setTimeout( () => setCssReady( true ), 50 );
		return () => {
			window.clearTimeout( t );
		};
	}, [ open, libraries ] );

	useEffect( () => {
		if ( parsed?.libraryId ) {
			setActiveLib( parsed.libraryId );
		}
	}, [ parsed?.libraryId ] );

	const activeLibrary =
		libraries.find( ( l ) => l.id === activeLib ) || libraries[ 0 ] || null;

	const currentLibrary =
		( parsed &&
			libraries.find( ( l ) => l.id === parsed.libraryId ) ) ||
		null;

	const filtered = useMemo( () => {
		const catalog = Array.isArray( activeLibrary?.catalog )
			? activeLibrary.catalog
			: [];
		const q = query.trim().toLowerCase();
		if ( ! q ) {
			return catalog;
		}
		return catalog.filter( ( item ) => {
			const hay = [
				item.id,
				item.label,
				...( Array.isArray( item.keywords ) ? item.keywords : [] ),
			]
				.join( ' ' )
				.toLowerCase();
			return hay.includes( q );
		} );
	}, [ activeLibrary, query ] );

	const visible = useMemo( () => {
		const q = query.trim();
		if (
			activeLibrary?.type === 'svg-inline' &&
			! q &&
			filtered.length > INLINE_PREVIEW_LIMIT
		) {
			return filtered.slice( 0, INLINE_PREVIEW_LIMIT );
		}
		return filtered;
	}, [ activeLibrary?.type, filtered, query ] );

	const currentHtml = current
		? renderIconHtml( current, 'font-size:18px;width:1em;height:1em' )
		: '';

	const title = label || __( 'Button icon', 'joc-blockora-morph' );

	return (
		<div className="bm-universal-icon-picker bm-btn-icon-picker">
			<Button
				size="small"
				variant="secondary"
				className="bm-btn-icon-picker__toggle"
				aria-expanded={ open }
				aria-label={
					current
						? __( 'Change icon', 'joc-blockora-morph' )
						: __( 'Add icon', 'joc-blockora-morph' )
				}
				label={
					current
						? __( 'Change icon', 'joc-blockora-morph' )
						: __( 'Add icon', 'joc-blockora-morph' )
				}
				showTooltip
				onClick={ () => setOpen( ( v ) => ! v ) }
			>
				<IconPreview
					html={ currentHtml }
					library={ currentLibrary }
					iconId={ parsed?.iconId }
				/>
			</Button>
			{ open ? (
				<Popover
					onClose={ () => setOpen( false ) }
					placement="bottom-end"
					focusOnMount="container"
				>
					<div
						className={
							'bm-universal-icon-picker__popover bm-btn-icon-picker__popover' +
							( cssReady ? ' is-css-ready' : '' )
						}
					>
						<div className="bm-btn-icon-picker__head">
							<strong>{ title }</strong>
							{ current ? (
								<Button
									size="small"
									variant="tertiary"
									isDestructive
									onClick={ () => {
										onChange( '' );
										setOpen( false );
									} }
								>
									{ __( 'Remove', 'joc-blockora-morph' ) }
								</Button>
							) : null }
						</div>

						{ libraries.length > 1 ? (
							<div
								className="bm-universal-icon-picker__tabs"
								role="tablist"
							>
								{ libraries.map( ( lib ) => (
									<button
										key={ lib.id }
										type="button"
										role="tab"
										aria-selected={ activeLib === lib.id }
										className={
											'bm-universal-icon-picker__tab' +
											( activeLib === lib.id
												? ' is-active'
												: '' )
										}
										onClick={ () => {
											setActiveLib( lib.id );
											setQuery( '' );
										} }
									>
										{ lib.label || lib.id }
									</button>
								) ) }
							</div>
						) : null }

						<TextControl
							className="bm-universal-icon-picker__search"
							value={ query }
							onChange={ setQuery }
							placeholder={ __(
								'Search icons…',
								'joc-blockora-morph'
							) }
							__nextHasNoMarginBottom
							__next40pxDefaultSize
						/>

						{ ! activeLibrary?.stylesheetUrl &&
						activeLibrary?.id !== 'dashicons' &&
						activeLibrary?.type !== 'svg-inline' &&
						activeLibrary?.type !== 'svg-sprite' ? (
							<p className="bm-universal-icon-picker__hint">
								{ __(
									'Add a stylesheet URL for this library in Global Settings → Icons to preview glyphs.',
									'joc-blockora-morph'
								) }
							</p>
						) : null }

						{ activeLibrary?.type === 'svg-inline' &&
						! query.trim() &&
						filtered.length > visible.length ? (
							<p className="bm-universal-icon-picker__hint">
								{ __(
									'Showing a sample — search to find more icons. Only selected icons load on the page.',
									'joc-blockora-morph'
								) }
							</p>
						) : null }

						<div
							className="bm-btn-icon-picker__grid bm-universal-icon-picker__grid"
							role="listbox"
							aria-label={ __( 'Icons', 'joc-blockora-morph' ) }
						>
							{ visible.map( ( item ) => {
								const ref = `${ activeLibrary.id }:${ item.id }`;
								const selected = current === ref;
								return (
									<button
										key={ ref }
										type="button"
										role="option"
										aria-selected={ selected }
										aria-label={ item.label || item.id }
										title={ item.label || item.id }
										className={
											'bm-btn-icon-picker__item' +
											( selected ? ' is-active' : '' )
										}
										onClick={ () => {
											onChange( ref );
											setOpen( false );
										} }
									>
										<IconGlyph
											library={ activeLibrary }
											iconId={ item.id }
										/>
									</button>
								);
							} ) }
							{ ! filtered.length ? (
								<p className="bm-universal-icon-picker__empty">
									{ __(
										'No icons match your search.',
										'joc-blockora-morph'
									) }
								</p>
							) : null }
						</div>
					</div>
				</Popover>
			) : null }
		</div>
	);
}

export { isValidIconRef as isValidDashicon } from '../../shared/iconRegistry';
