import { createPortal, useEffect, useMemo, useRef, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { api } from '../api';
import { isProActive } from '../extensibility';
import IconPicker from './IconPicker';
import PreviewFrame from './PreviewFrame';
import VariantLayerThumb from './VariantLayerThumb';
import Notice from './ui/Notice';
import { renderPreview } from './renderPreview';
import HorizontalScrollRail from '../../shared/HorizontalScrollRail';

export { renderPreview } from './renderPreview';

export default function PreviewModal( {
	block,
	onClose,
	onImport,
	importing,
	browseList = null,
	onBrowseSelect = null,
	/**
	 * Optional Owner Library action — replaces the Import form.
	 * { title?, description?, label, busy?, onClick( block ) }
	 */
	primaryAction = null,
} ) {
	const [ name, setName ] = useState( '' );
	const [ icon, setIcon ] = useState( 'screenoptions' );
	const [ error, setError ] = useState( '' );
	const [ validating, setValidating ] = useState( false );
	const [ viewport, setViewport ] = useState( 'desktop' );
	const [ sidebarOpen, setSidebarOpen ] = useState( false );
	const [ isFullscreen, setIsFullscreen ] = useState( false );
	const [ activeLayerId, setActiveLayerId ] = useState( 'original' );
	const [ layersOpen, setLayersOpen ] = useState( true );
	const nameInputRef = useRef( null );

	const layers = useMemo( () => {
		if ( ! block ) {
			return [];
		}
		const variants = Array.isArray( block.variants ) ? block.variants : [];
		const original = {
			...block,
			__layerId: 'original',
			__layerLabel: __( 'Original', 'joc-blockora-morph' ),
		};
		const variantLayers = variants.map( ( variantPack, index ) => {
			const slug = variantPack.ownerSlug || variantPack.slug || index;
			const variant =
				variantPack.ownerVariant || variantPack.variant || 'default';
			return {
				...variantPack,
				__layerId: `variant:${ slug }:${ variant }`,
				__layerLabel:
					variantPack.name ||
					variantPack.title ||
					__( 'Variant', 'joc-blockora-morph' ),
			};
		} );
		return [ original, ...variantLayers ];
	}, [ block ] );

	const activePack = useMemo( () => {
		if ( ! layers.length ) {
			return block;
		}
		return (
			layers.find( ( layer ) => layer.__layerId === activeLayerId ) ||
			layers[ 0 ]
		);
	}, [ layers, activeLayerId, block ] );

	const hasVariantLayers = layers.length > 1;
	const proLocked = Boolean( activePack?.isPro ) && ! isProActive();

	const browseItems = Array.isArray( browseList ) ? browseList : [];
	const browseIndex = useMemo( () => {
		if ( ! block || ! browseItems.length ) {
			return -1;
		}
		return browseItems.findIndex( ( item ) => item?.id === block.id );
	}, [ block, browseItems ] );
	const canBrowse =
		typeof onBrowseSelect === 'function' &&
		browseIndex >= 0 &&
		browseItems.length > 1;

	const preview = useMemo(
		() => {
			if ( ! activePack ) {
				return { __html: '', styleCss: '' };
			}
			const rendered = renderPreview(
						activePack.markup,
						activePack.defaultAttrs,
						activePack.cssVars,
						activePack.fieldSchema || [],
						viewport
				  );
			const isAccordion =
				String( activePack.slug || '' ).toLowerCase() === 'accordion' ||
				String( activePack.markup || '' ).includes( 'bm-accordion' );
			if ( ! isAccordion ) {
				return rendered;
			}
			return {
				...rendered,
				styleCss: `${ rendered.styleCss || '' }

.bm-preview-root > .bm-accordion {
	min-height: calc(100vh - 44px);
	box-sizing: border-box;
}`,
			};
		},
		[ activePack, viewport ]
	);

	useEffect( () => {
		setActiveLayerId( 'original' );
		setLayersOpen( true );
	}, [ block?.id ] );

	useEffect( () => {
		if ( ! activePack ) {
			return;
		}
		setName( `${ activePack.name || activePack.title || '' }` );
		setIcon( 'screenoptions' );
		setError( '' );
		setValidating( false );
	}, [ activePack?.__layerId, activePack?.name, activePack?.title ] );

	useEffect( () => {
		if ( ! block ) {
			return;
		}
		setSidebarOpen( false );
		setIsFullscreen( false );
	}, [ block?.id ] );

	useEffect( () => {
		if ( ! sidebarOpen || proLocked || primaryAction?.onClick ) {
			return;
		}
		const id = window.setTimeout( () => {
			nameInputRef.current?.focus?.();
			nameInputRef.current?.select?.();
		}, 320 );
		return () => window.clearTimeout( id );
	}, [ sidebarOpen, block?.id, proLocked, primaryAction?.onClick ] );

	useEffect( () => {
		if ( ! block ) {
			return;
		}
		const isTypingTarget = ( el ) => {
			if ( ! el || typeof el !== 'object' ) {
				return false;
			}
			const tag = String( el.tagName || '' ).toLowerCase();
			return (
				tag === 'input' ||
				tag === 'textarea' ||
				tag === 'select' ||
				el.isContentEditable
			);
		};
		const onKey = ( e ) => {
			if ( e.key === 'Escape' && ! importing && ! validating ) {
				if ( isFullscreen ) {
					setIsFullscreen( false );
					return;
				}
				if ( layersOpen ) {
					setLayersOpen( false );
					return;
				}
				if ( sidebarOpen ) {
					setSidebarOpen( false );
					return;
				}
				onClose();
				return;
			}
			if ( ! canBrowse || importing || validating ) {
				return;
			}
			if ( isTypingTarget( e.target ) ) {
				return;
			}
			if ( e.key === 'ArrowLeft' ) {
				e.preventDefault();
				onBrowseSelect(
					browseItems[
						( browseIndex - 1 + browseItems.length ) %
							browseItems.length
					]
				);
			} else if ( e.key === 'ArrowRight' ) {
				e.preventDefault();
				onBrowseSelect(
					browseItems[ ( browseIndex + 1 ) % browseItems.length ]
				);
			}
		};
		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 );
		};
	}, [
		block,
		onClose,
		importing,
		validating,
		canBrowse,
		browseIndex,
		browseItems,
		onBrowseSelect,
		isFullscreen,
		sidebarOpen,
		layersOpen,
	] );

	if ( ! block ) {
		return null;
	}

	const showNameError = ( message ) => {
		setSidebarOpen( true );
		setError( message );
		window.requestAnimationFrame( () => {
			nameInputRef.current?.focus?.();
			nameInputRef.current?.select?.();
		} );
	};

	const requestImport = async () => {
		if ( proLocked ) {
			return;
		}
		const trimmed = name.trim();
		if ( ! trimmed ) {
			showNameError( __( 'Block name is required.', 'joc-blockora-morph' ) );
			return;
		}

		setValidating( true );
		setError( '' );
		try {
			const result = await api.get(
				`/user-blocks/check-name?name=${ encodeURIComponent( trimmed ) }`
			);
			if ( ! result?.valid ) {
				showNameError(
					result?.message ||
						__( 'Please enter a valid unique block name.', 'joc-blockora-morph' )
				);
				return;
			}
			onImport( activePack, { name: trimmed, icon } );
		} catch ( e ) {
			showNameError(
				e?.message ||
					__( 'Could not validate block name. Try again.', 'joc-blockora-morph' )
			);
		} finally {
			setValidating( false );
		}
	};

	const goAdjacent = ( delta ) => {
		if ( ! canBrowse ) {
			return;
		}
		onBrowseSelect(
			browseItems[
				( browseIndex + delta + browseItems.length ) % browseItems.length
			]
		);
	};

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

	const busy = importing || validating || Boolean( primaryAction?.busy );
	const useCustomAction = Boolean( primaryAction?.onClick );

	return createPortal(
		<>
			<div
				className={
					'bm-modal-root bm-fade fixed inset-0 z-[100000] flex items-center justify-center overflow-visible font-sans' +
					( isFullscreen
						? ' px-0 py-0'
						: ' px-10 py-3 sm:px-14 sm:py-6' )
				}
				role="dialog"
				aria-modal="true"
			>
				<div
					className="bm-modal-backdrop transition-opacity duration-200"
					onClick={ busy ? undefined : onClose }
				/>
				<div
					className={
						'bm-rise bm-preview-modal relative z-10 w-full' +
						( isFullscreen
							? ' bm-preview-modal--fullscreen h-[100dvh] max-w-none'
							: ' h-[min(900px,calc(100dvh-1.5rem))] max-w-[1440px] md:h-[min(900px,94vh)]' )
					}
				>
					{ canBrowse ? (
						<>
							<button
								type="button"
								className="bm-preview-nav__arrow bm-preview-nav__arrow--prev"
								onClick={ () => goAdjacent( -1 ) }
								disabled={ busy }
								aria-label={ __(
									'Previous template',
									'joc-blockora-morph'
								) }
							>
								<span
									className="dashicons dashicons-arrow-left-alt2"
									aria-hidden="true"
								/>
							</button>
							<button
								type="button"
								className="bm-preview-nav__arrow bm-preview-nav__arrow--next"
								onClick={ () => goAdjacent( 1 ) }
								disabled={ busy }
								aria-label={ __(
									'Next template',
									'joc-blockora-morph'
								) }
							>
								<span
									className="dashicons dashicons-arrow-right-alt2"
									aria-hidden="true"
								/>
							</button>
							<span className="bm-preview-nav__count" aria-live="polite">
								{ browseIndex + 1 } / { browseItems.length }
							</span>
						</>
					) : null }
					<div
						className={
							'bm-preview-modal__body flex h-full w-full flex-col overflow-hidden rounded-xl border border-outline-variant/30 bg-surface-lowest shadow-card' +
							( sidebarOpen ? ' is-sidebar-open' : '' )
						}
					>
					<div className="bm-preview-modal__stage flex min-h-0 min-w-0 flex-1 flex-col bg-surface-low max-md:min-h-[min(52dvh,420px)]">
						<header className="bm-preview-modal__header flex shrink-0 items-center gap-3 border-b border-outline-variant/20 bg-surface-lowest px-4 py-3 sm:px-5 sm:py-4">
							<div className="min-w-0 flex-1">
								<p className="mb-1 text-caps-micro font-bold uppercase tracking-widest text-outline">
									{ activePack.categoryName ||
										block.categoryName }
								</p>
								<h2 className="m-0 text-headline-lg text-on-surface">
									{ activePack.name ||
										activePack.title ||
										block.name }
								</h2>
								<p className="mt-1 mb-0 line-clamp-2 text-body-md text-on-surface-variant">
									{ activePack.description ||
										block.description }
								</p>
							</div>
							<div className="bm-preview-modal__header-actions flex shrink-0 items-center gap-2">
								<button
									type="button"
									className={
										'bm-btn bm-btn--ghost bm-btn--lg bm-preview-modal__icon-btn' +
										( isFullscreen ? ' is-active' : '' )
									}
									aria-pressed={ isFullscreen }
									aria-label={
										isFullscreen
											? __(
													'Exit full screen',
													'joc-blockora-morph'
											  )
											: __(
													'Full screen',
													'joc-blockora-morph'
											  )
									}
									title={
										isFullscreen
											? __(
													'Exit full screen',
													'joc-blockora-morph'
											  )
											: __(
													'Full screen',
													'joc-blockora-morph'
											  )
									}
									onClick={ () =>
										setIsFullscreen( ( on ) => ! on )
									}
								>
									<span
										className={
											'dashicons dashicons-' +
											( isFullscreen
												? 'fullscreen-exit-alt'
												: 'fullscreen-alt' )
										}
										aria-hidden="true"
									/>
								</button>
								<button
									type="button"
									className={
										sidebarOpen
											? 'bm-btn bm-btn--ghost bm-btn--lg'
											: 'bm-btn bm-btn--primary bm-btn--lg'
									}
									aria-pressed={ sidebarOpen }
									onClick={ () =>
										setSidebarOpen( ( open ) => ! open )
									}
								>
									<span
										className={
											'dashicons dashicons-' +
											( sidebarOpen
												? 'hidden'
												: 'plus-alt' )
										}
										aria-hidden="true"
									/>
									{ sidebarOpen
										? __(
												'Hide panel',
												'joc-blockora-morph'
										  )
										: __(
												'Add to My Blocks',
												'joc-blockora-morph'
										  ) }
								</button>
								<button
									type="button"
									className="bm-preview-modal__sidebar-close bm-preview-modal__sidebar-close--header"
									onClick={ busy ? undefined : onClose }
									disabled={ busy }
									aria-label={ __(
										'Close',
										'joc-blockora-morph'
									) }
								>
									<span
										className="dashicons dashicons-no-alt"
										aria-hidden="true"
									/>
								</button>
							</div>
						</header>
						<PreviewFrame
							key={ activeLayerId }
							html={ preview }
							className="min-h-0 flex-1"
							frameClassName="bm-preview-variant-enter"
							viewport={ viewport }
							onViewportChange={ setViewport }
						/>
						{ hasVariantLayers ? (
							<div
								className={
									'bm-preview-layers' +
									( layersOpen ? ' is-open' : ' is-closed' )
								}
							>
								<div className="bm-preview-layers__shell">
									<button
										type="button"
										className="bm-preview-layers__toggle"
										aria-expanded={ layersOpen }
										aria-controls="bm-preview-layers-panel"
										disabled={ busy }
										onClick={ () =>
											setLayersOpen( ( open ) => ! open )
										}
									>
										<span
											className={
												'dashicons dashicons-arrow-' +
												( layersOpen ? 'down' : 'up' ) +
												'-alt2'
											}
											aria-hidden="true"
										/>
										<span className="bm-preview-layers__toggle-label">
											{ layersOpen
												? __(
														'Hide variants',
														'joc-blockora-morph'
												  )
												: __(
														'Show variants',
														'joc-blockora-morph'
												  ) }
										</span>
										<span className="bm-preview-layers__toggle-count">
											{ layers.length }
										</span>
									</button>
									<div
										id="bm-preview-layers-panel"
										className="bm-preview-layers__drawer"
										aria-hidden={ ! layersOpen }
									>
										<div className="bm-preview-layers__drawer-inner">
											<HorizontalScrollRail
												trackClassName="bm-preview-layers__track"
												remeasureKey={ `${ layers.length }:${ layersOpen }` }
												trackProps={ {
													role: 'listbox',
													'aria-label': __(
														'Template variants',
														'joc-blockora-morph'
													),
												} }
											>
												{ layers.map( ( layer ) => {
													const selected =
														layer.__layerId ===
														activeLayerId;
													const onActivate = () => {
														if ( ! layersOpen ) {
															setLayersOpen(
																true
															);
															return;
														}
														setActiveLayerId(
															layer.__layerId
														);
													};
													return (
														<div
															key={
																layer.__layerId
															}
															role="option"
															tabIndex={
																busy ||
																! layersOpen
																	? -1
																	: 0
															}
															aria-selected={
																selected
															}
															aria-disabled={
																busy
															}
															className={
																'bm-preview-layers__card' +
																( selected
																	? ' is-selected'
																	: '' )
															}
															title={
																layer.__layerLabel
															}
															onClick={
																busy
																	? undefined
																	: onActivate
															}
															onKeyDown={
																busy
																	? undefined
																	: (
																			e
																	  ) => {
																			if (
																				e.key ===
																					'Enter' ||
																				e.key ===
																					' '
																			) {
																				e.preventDefault();
																				onActivate();
																			}
																	  }
															}
														>
															<VariantLayerThumb
																block={ layer }
																label={
																	layer.__layerLabel
																}
															/>
															<span className="bm-preview-layers__label">
																{
																	layer.__layerLabel
																}
															</span>
														</div>
													);
												} ) }
											</HorizontalScrollRail>
										</div>
									</div>
								</div>
							</div>
						) : null }
					</div>
					<aside
						className={
							'bm-preview-modal__sidebar' +
							( sidebarOpen ? ' is-open' : '' )
						}
						aria-hidden={ ! sidebarOpen }
					>
						<div className="bm-preview-modal__sidebar-inner flex h-full max-h-[48%] shrink-0 flex-col gap-3 overflow-y-auto p-4 sm:p-5 md:max-h-none">
						<div className="flex items-start justify-between gap-2">
							<p className="m-0 text-caps-micro font-bold uppercase tracking-widest text-outline">
								{ useCustomAction
									? __( 'Owner Library', 'joc-blockora-morph' )
									: __( 'Import', 'joc-blockora-morph' ) }
							</p>
							<button
								type="button"
								className="bm-preview-modal__sidebar-close"
								onClick={ () => setSidebarOpen( false ) }
								aria-label={ __(
									'Hide panel',
									'joc-blockora-morph'
								) }
								tabIndex={ sidebarOpen ? 0 : -1 }
							>
								<span
									className="dashicons dashicons-no-alt"
									aria-hidden="true"
								/>
							</button>
						</div>
						{ useCustomAction ? (
							<>
								<h3 className="m-0 text-headline-md text-on-surface">
									{ primaryAction.title ||
										__( 'Preview', 'joc-blockora-morph' ) }
								</h3>
								{ primaryAction.description ? (
									<p className="m-0 text-body-md text-on-surface-variant">
										{ primaryAction.description }
									</p>
								) : null }
								<div className="flex items-center justify-between border-y border-outline-variant/20 py-3 text-body-md">
									<span className="text-on-surface-variant">
										{ __(
											'Library variant',
											'joc-blockora-morph'
										) }
									</span>
									<strong className="text-on-surface">
										{ activePack.variant || block.variant }
									</strong>
								</div>
								<div className="mt-auto flex flex-col gap-2 pt-2">
									<button
										type="button"
										className="bm-btn bm-btn--primary bm-btn--block"
										onClick={ () =>
											primaryAction.onClick( block )
										}
										disabled={ busy }
									>
										{ primaryAction.busy
											? primaryAction.busyLabel ||
											  __(
													'Working…',
													'joc-blockora-morph'
											  )
											: primaryAction.label ||
											  __(
													'Continue',
													'joc-blockora-morph'
											  ) }
									</button>
									<button
										type="button"
										className="bm-btn bm-btn--ghost bm-btn--block"
										onClick={ onClose }
										disabled={ busy }
									>
										{ __( 'Close', 'joc-blockora-morph' ) }
									</button>
								</div>
							</>
						) : (
							<>
								<h3 className="m-0 text-headline-md text-on-surface">
									{ __(
										'Add to My Blocks',
										'joc-blockora-morph'
									) }
								</h3>
								{ proLocked ? (
									<>
										<Notice variant="warning">
											{ __(
												'This template is part of JOC Blockora Morph Pro. Activate Pro to import it.',
												'joc-blockora-morph'
											) }
										</Notice>
										<div className="mt-auto flex flex-col gap-2 pt-2">
											<button
												type="button"
												className="bm-btn bm-btn--ghost bm-btn--block"
												onClick={ onClose }
											>
												{ __(
													'Close',
													'joc-blockora-morph'
												) }
											</button>
										</div>
									</>
								) : (
									<>
										<p className="m-0 text-body-md text-on-surface-variant">
											{ __(
												'Give this import a unique name and icon. That name is what appears in the Gutenberg block inserter.',
												'joc-blockora-morph'
											) }
										</p>

										<label>
											<span className="bm-field-label">
												{ __(
													'Block name',
													'joc-blockora-morph'
												) }{ ' ' }
												<em className="not-italic text-red-600">
													*
												</em>
											</span>
											<input
												ref={ nameInputRef }
												type="text"
												className={
													error
														? 'bm-field-input is-invalid'
														: 'bm-field-input'
												}
												value={ name }
												required
												aria-invalid={ !! error }
												aria-describedby={
													error
														? 'bm-import-name-error'
														: undefined
												}
												placeholder={ __(
													'e.g. Homepage Hero',
													'joc-blockora-morph'
												) }
												onChange={ ( e ) => {
													setName( e.target.value );
													if ( error ) {
														setError( '' );
													}
												} }
												onKeyDown={ ( e ) => {
													if ( e.key === 'Enter' ) {
														e.preventDefault();
														requestImport();
													}
												} }
											/>
										</label>

										{ error ? (
											<div id="bm-import-name-error">
												<Notice variant="danger">
													{ error }
												</Notice>
											</div>
										) : null }

										<IconPicker
											label={ __(
												'Gutenberg icon',
												'joc-blockora-morph'
											) }
											value={ icon }
											onChange={ setIcon }
										/>

										<div className="flex items-center justify-between border-y border-outline-variant/20 py-3 text-body-md">
											<span className="text-on-surface-variant">
												{ __(
													'Library variant',
													'joc-blockora-morph'
												) }
											</span>
											<strong className="text-on-surface">
												{ activePack.variant || block.variant }
											</strong>
										</div>

										<div className="mt-auto flex flex-col gap-2 pt-2">
											<button
												type="button"
												className="bm-btn bm-btn--primary bm-btn--block"
												onClick={ requestImport }
												disabled={ busy }
											>
												{ validating
													? __(
															'Checking name…',
															'joc-blockora-morph'
													  )
													: importing
													? __(
															'Importing…',
															'joc-blockora-morph'
													  )
													: __(
															'Import block',
															'joc-blockora-morph'
													  ) }
											</button>
											<button
												type="button"
												className="bm-btn bm-btn--ghost bm-btn--block"
												onClick={ onClose }
												disabled={ busy }
											>
												{ __(
													'Close',
													'joc-blockora-morph'
												) }
											</button>
										</div>
									</>
								) }
							</>
						) }
						</div>
					</aside>
					</div>
				</div>
			</div>
		</>,
		portalTarget
	);
}
