import { createPortal, useEffect, useMemo, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import BlockIdentityIcon from './BlockIdentityIcon';
import { blockCategorySlugs, blockMatchesCategory } from './BlocksListFilters';

/**
 * Modal picker for My Blocks — category sidebar + search, like the library.
 *
 * @param {Object}   props
 * @param {Array}    props.blocks     User (Gutenberg) blocks.
 * @param {boolean}  props.creating   Whether create is in progress.
 * @param {Function} props.onClose    Close handler.
 * @param {Function} props.onSelect   Called with selected block when confirmed.
 */
export default function PickUserBlockModal( {
	blocks = [],
	creating = false,
	onClose,
	onSelect,
} ) {
	const [ activeCat, setActiveCat ] = useState( 'all' );
	const [ query, setQuery ] = useState( '' );
	const [ selectedId, setSelectedId ] = useState( '' );

	useEffect( () => {
		const onKey = ( e ) => {
			if ( e.key === 'Escape' && ! creating ) {
				onClose();
			}
		};
		const prevOverflow = document.body.style.overflow;
		document.body.style.overflow = 'hidden';
		window.addEventListener( 'keydown', onKey );
		return () => {
			document.body.style.overflow = prevOverflow;
			window.removeEventListener( 'keydown', onKey );
		};
	}, [ creating, onClose ] );

	const categories = useMemo( () => {
		const map = new Map();
		blocks.forEach( ( b ) => {
			blockCategorySlugs( b ).forEach( ( slug ) => {
				const name =
					slug === String( b.categorySlug || '' ).trim()
						? b.categoryName ||
						  __( 'Uncategorized', 'joc-blockora-morph' )
						: slug === 'uncategorized'
							? __( 'Uncategorized', 'joc-blockora-morph' )
							: slug;
				const prev = map.get( slug );
				if ( prev ) {
					prev.count += 1;
				} else {
					map.set( slug, { slug, name, count: 1 } );
				}
			} );
		} );
		return Array.from( map.values() ).sort( ( a, b ) =>
			a.name.localeCompare( b.name )
		);
	}, [ blocks ] );

	const filtered = useMemo( () => {
		const q = query.trim().toLowerCase();
		return blocks.filter( ( b ) => {
			if ( activeCat !== 'all' && ! blockMatchesCategory( b, activeCat ) ) {
				return false;
			}
			if ( ! q ) {
				return true;
			}
			const hay = `${ b.name || '' } ${ b.systemName || '' } ${
				b.variant || ''
			} ${ b.categoryName || '' } ${ ( b.categorySlugs || [] ).join( ' ' ) }`.toLowerCase();
			return hay.includes( q );
		} );
	}, [ blocks, activeCat, query ] );

	const selected = blocks.find( ( b ) => String( b.id ) === String( selectedId ) );

	const confirm = () => {
		if ( ! selected || creating ) {
			return;
		}
		onSelect( selected );
	};

	const portalTarget =
		document.getElementById( 'joc-blockora-morph-app' ) || document.body;

	const activeLabel =
		activeCat === 'all'
			? __( 'All blocks', 'joc-blockora-morph' )
			: categories.find( ( c ) => c.slug === activeCat )?.name || activeCat;

	return createPortal(
		<div
			className="bm-modal-root bm-fade fixed inset-0 z-[100000] flex items-center justify-center p-4 font-sans sm:p-6"
			role="dialog"
			aria-modal="true"
			aria-labelledby="bm-pick-block-title"
		>
			<div
				className="bm-modal-backdrop"
				onClick={ creating ? undefined : onClose }
			/>
			<div className="bm-rise relative z-10 flex h-[min(720px,90vh)] w-full max-w-[920px] flex-col overflow-hidden rounded-xl border border-outline-variant/30 bg-surface-lowest shadow-card">
				<header className="flex shrink-0 flex-col gap-3 border-b border-outline-variant/20 px-5 py-4 sm:flex-row sm:items-center sm:justify-between">
					<div className="min-w-0">
						<p className="mb-1 text-caps-micro font-bold uppercase tracking-widest text-outline">
							{ __( 'Create shortcode', 'joc-blockora-morph' ) }
						</p>
						<h2
							id="bm-pick-block-title"
							className="m-0 truncate text-headline-lg text-on-surface"
						>
							{ __( 'Choose a Gutenberg block', 'joc-blockora-morph' ) }
						</h2>
					</div>
					<label className="group relative w-full sm:w-72">
						<span className="screen-reader-text">
							{ __( 'Search blocks', 'joc-blockora-morph' ) }
						</span>
						<span
							className="dashicons dashicons-search pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-outline transition-colors duration-200 group-focus-within:text-primary"
							aria-hidden="true"
						/>
						<input
							type="search"
							value={ query }
							onChange={ ( e ) => setQuery( e.target.value ) }
							placeholder={ __( 'Search my blocks…', 'joc-blockora-morph' ) }
							className="w-full rounded-xl border border-outline-variant bg-white py-2.5 pl-10 pr-4 text-[13px] text-on-surface outline-none transition-all duration-200 focus:border-primary focus:ring-1 focus:ring-primary"
							autoFocus
						/>
					</label>
				</header>

				<div className="flex min-h-0 flex-1">
					<aside
						className="hidden w-52 shrink-0 flex-col border-r border-outline-variant/20 bg-surface-low/40 p-3 sm:flex"
						aria-label={ __( 'Categories', 'joc-blockora-morph' ) }
					>
						<p className="mb-2 px-2 text-caps-micro font-bold uppercase tracking-widest text-outline">
							{ __( 'Categories', 'joc-blockora-morph' ) }
						</p>
						<button
							type="button"
							className={
								activeCat === 'all' ? 'bm-cat-link is-active' : 'bm-cat-link'
							}
							onClick={ () => setActiveCat( 'all' ) }
						>
							<span>{ __( 'All blocks', 'joc-blockora-morph' ) }</span>
							<em className="bm-cat-count">{ blocks.length }</em>
						</button>
						{ categories.map( ( cat ) => (
							<button
								key={ cat.slug }
								type="button"
								className={
									activeCat === cat.slug
										? 'bm-cat-link is-active'
										: 'bm-cat-link'
								}
								onClick={ () => setActiveCat( cat.slug ) }
							>
								<span>{ cat.name }</span>
								<em className="bm-cat-count">{ cat.count }</em>
							</button>
						) ) }
					</aside>

					<div className="flex min-w-0 flex-1 flex-col">
						<div className="flex shrink-0 items-center justify-between gap-3 border-b border-outline-variant/15 px-4 py-2.5 sm:hidden">
							<label className="flex min-w-0 flex-1 items-center gap-2">
								<span className="shrink-0 text-label-md text-on-surface-variant">
									{ __( 'Category', 'joc-blockora-morph' ) }
								</span>
								<select
									className="bm-field-input min-w-0 flex-1"
									value={ activeCat }
									onChange={ ( e ) => setActiveCat( e.target.value ) }
								>
									<option value="all">
										{ __( 'All blocks', 'joc-blockora-morph' ) } (
										{ blocks.length })
									</option>
									{ categories.map( ( cat ) => (
										<option key={ cat.slug } value={ cat.slug }>
											{ cat.name } ({ cat.count })
										</option>
									) ) }
								</select>
							</label>
						</div>

						{ activeCat !== 'all' && (
							<div className="flex shrink-0 items-center justify-between gap-4 border-b border-outline-variant/15 bg-surface-low/30 px-4 py-2 text-body-md text-on-surface-variant">
								<span>
									{ __( 'Showing', 'joc-blockora-morph' ) }{ ' ' }
									<strong className="text-on-surface">{ activeLabel }</strong>
								</span>
								<button
									type="button"
									className="text-label-lg text-primary-interactive hover:text-primary hover:underline"
									onClick={ () => setActiveCat( 'all' ) }
								>
									{ __( 'Clear filter', 'joc-blockora-morph' ) }
								</button>
							</div>
						) }

						<ul className="m-0 min-h-0 flex-1 list-none overflow-y-auto p-0">
							{ filtered.length === 0 ? (
								<li className="px-5 py-10 text-center text-body-md text-on-surface-variant">
									{ __( 'No blocks match your search.', 'joc-blockora-morph' ) }
								</li>
							) : (
								filtered.map( ( block ) => {
									const isSelected =
										String( selectedId ) === String( block.id );
									return (
										<li key={ block.id } className="m-0 list-none border-b border-outline-variant/15 last:border-b-0">
											<button
												type="button"
												className={
													isSelected
														? 'bm-pick-block-row is-selected'
														: 'bm-pick-block-row'
												}
												onClick={ () =>
													setSelectedId( String( block.id ) )
												}
												onDoubleClick={ () => {
													setSelectedId( String( block.id ) );
													onSelect( block );
												} }
												disabled={ creating }
											>
												<BlockIdentityIcon
													icon={
														block.icon ||
														'screenoptions'
													}
													className="bm-pick-block-row__icon"
												/>
												<span className="min-w-0 flex-1 text-left">
													<strong className="block truncate text-body-md text-on-surface">
														{ block.name }
													</strong>
													<small className="mt-0.5 block truncate text-label-md text-on-surface-variant">
														{ block.categoryName ||
															__(
																'Uncategorized',
																'joc-blockora-morph'
															) }
														{ block.variant
															? ` · ${ block.variant }`
															: '' }
													</small>
												</span>
												{ isSelected && (
													<span
														className="dashicons dashicons-yes-alt text-primary"
														aria-hidden="true"
													/>
												) }
											</button>
										</li>
									);
								} )
							) }
						</ul>
					</div>
				</div>

				<footer className="flex shrink-0 flex-wrap items-center justify-end gap-2 border-t border-outline-variant/20 bg-surface-low/60 px-5 py-3">
					<button
						type="button"
						className="bm-btn bm-btn--ghost bm-btn--sm"
						onClick={ onClose }
						disabled={ creating }
					>
						{ __( 'Cancel', 'joc-blockora-morph' ) }
					</button>
					<button
						type="button"
						className="bm-btn bm-btn--primary bm-btn--sm"
						onClick={ confirm }
						disabled={ ! selected || creating }
					>
						{ creating
							? __( 'Creating…', 'joc-blockora-morph' )
							: __( 'Create shortcode', 'joc-blockora-morph' ) }
					</button>
				</footer>
			</div>
		</div>,
		portalTarget
	);
}
