/**
 * When inserting a JBM Library block that has Owner variants, intercept
 * inserter click and canvas drag alike: remove the provisional block, show a
 * live-preview picker modal, then insert the chosen pack (or nothing on cancel).
 */

import { Button, Modal } from '@wordpress/components';
import {
	createElement,
	useEffect,
	useMemo,
	useRef,
	useState,
} from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { registerPlugin } from '@wordpress/plugins';
import { useDispatch, select, subscribe } from '@wordpress/data';
import { createBlock } from '@wordpress/blocks';
import { brandBlockIcon } from '../shared/brandLogo';
import HorizontalScrollRail from '../shared/HorizontalScrollRail';
import VariantLayerThumb from '../admin/components/VariantLayerThumb';
import {
	LIB_PREFIX,
	catalogByName,
	skipPickerOnce,
} from './libraryVariants';

function flattenBlocks( blocks ) {
	const out = [];
	const walk = ( list ) => {
		( list || [] ).forEach( ( block ) => {
			out.push( block );
			if ( block.innerBlocks?.length ) {
				walk( block.innerBlocks );
			}
		} );
	};
	walk( blocks );
	return out;
}

function VariantInsertPicker() {
	const [ session, setSession ] = useState( null );
	const [ selectedName, setSelectedName ] = useState( '' );
	const handledRef = useRef( new Set() );
	const { removeBlock, insertBlocks } = useDispatch( 'core/block-editor' );

	const options = useMemo( () => {
		if ( ! session?.parentMeta ) {
			return [];
		}
		const parent = session.parentMeta;
		const variants = Array.isArray( parent.variants ) ? parent.variants : [];
		return [
			{
				...parent,
				name: parent.name,
				title:
					parent.title ||
					__( 'Original', 'joc-blockora-morph' ),
				isOriginal: true,
			},
			...variants.map( ( variant ) => ( {
				...variant,
				name: variant.name,
				title:
					variant.title ||
					variant.systemName ||
					__( 'Variant', 'joc-blockora-morph' ),
				isOriginal: false,
			} ) ),
		];
	}, [ session ] );
	const selectedOption = useMemo(
		() =>
			options.find( ( option ) => option.name === selectedName ) ||
			options[ 0 ] ||
			null,
		[ options, selectedName ]
	);

	useEffect( () => {
		const unsubscribe = subscribe( () => {
			const be = select( 'core/block-editor' );
			if ( ! be || session ) {
				return;
			}
			const catalog = catalogByName();
			const flat = flattenBlocks( be.getBlocks() );
			for ( const block of flat ) {
				if ( ! block?.name || ! block.name.startsWith( LIB_PREFIX ) ) {
					continue;
				}
				if ( handledRef.current.has( block.clientId ) ) {
					continue;
				}
				if ( skipPickerOnce.has( block.name ) ) {
					skipPickerOnce.delete( block.name );
					handledRef.current.add( block.clientId );
					continue;
				}
				const meta = catalog.get( block.name );
				if (
					! meta ||
					! Array.isArray( meta.variants ) ||
					! meta.variants.length
				) {
					handledRef.current.add( block.clientId );
					continue;
				}

				handledRef.current.add( block.clientId );
				const rootClientId = be.getBlockRootClientId( block.clientId );
				const index = be.getBlockIndex( block.clientId, rootClientId );
				removeBlock( block.clientId, false );
				setSelectedName( meta.name );
				setSession( {
					parentMeta: meta,
					rootClientId: rootClientId || undefined,
					index: typeof index === 'number' ? index : undefined,
				} );
				break;
			}
		} );
		return unsubscribe;
	}, [ removeBlock, session ] );

	const close = () => {
		setSession( null );
		setSelectedName( '' );
	};

	const confirm = () => {
		if ( ! session || ! selectedName ) {
			close();
			return;
		}
		skipPickerOnce.add( selectedName );
		const next = createBlock( selectedName );
		insertBlocks( next, session.index, session.rootClientId, false );
		close();
	};

	if ( ! session ) {
		return null;
	}

	return createElement(
		Modal,
		{
			title: __( 'Choose a template variant', 'joc-blockora-morph' ),
			onRequestClose: close,
			className: 'jocbm-variant-insert-modal',
		},
		createElement(
			'div',
			{
				className: 'jocbm-variant-insert-modal__stage',
			},
			createElement(
				'div',
				{ className: 'jocbm-variant-insert-modal__stage-head' },
				createElement(
					'span',
					{ className: 'jocbm-variant-insert-modal__badge' },
					selectedOption?.isOriginal
						? __( 'Original', 'joc-blockora-morph' )
						: __( 'Variant', 'joc-blockora-morph' )
				),
				createElement(
					'strong',
					{ className: 'jocbm-variant-insert-modal__active-title' },
					selectedOption?.title || ''
				)
			),
			createElement(
				'div',
				{
					key: selectedOption?.name || 'preview',
					className: 'jocbm-variant-insert-modal__preview',
				},
				selectedOption
					? createElement( VariantLayerThumb, {
							block: selectedOption,
							label: selectedOption.title,
							scrollable: true,
					  } )
					: null
			)
		),
		createElement(
			HorizontalScrollRail,
			{
				className: 'jocbm-variant-insert-modal__rail-wrap',
				trackClassName: 'jocbm-variant-insert-modal__rail',
				remeasureKey: options.length,
				trackProps: {
					role: 'listbox',
					'aria-label': __(
						'Template variants',
						'joc-blockora-morph'
					),
				},
			},
			options.map( ( option ) => {
				const selected = selectedName === option.name;
				return createElement(
					'div',
					{
						key: option.name,
						role: 'option',
						tabIndex: 0,
						'aria-selected': selected,
						className:
							'jocbm-variant-insert-modal__card' +
							( selected ? ' is-selected' : '' ),
						onClick: () => setSelectedName( option.name ),
						onKeyDown: ( e ) => {
							if ( e.key === 'Enter' || e.key === ' ' ) {
								e.preventDefault();
								setSelectedName( option.name );
							}
						},
					},
					createElement(
						'span',
						{ className: 'jocbm-variant-insert-modal__thumb' },
						createElement( VariantLayerThumb, {
							block: option,
							label: option.title,
						} )
					),
					createElement(
						'span',
						{ className: 'jocbm-variant-insert-modal__badge' },
						option.isOriginal
							? __( 'Original', 'joc-blockora-morph' )
							: __( 'Variant', 'joc-blockora-morph' )
					),
					createElement(
						'strong',
						{ className: 'jocbm-variant-insert-modal__title' },
						option.title
					)
				);
			} )
		),
		createElement(
			'div',
			{ className: 'jocbm-variant-insert-modal__actions' },
			createElement(
				Button,
				{ variant: 'tertiary', onClick: close },
				__( 'Cancel', 'joc-blockora-morph' )
			),
			createElement(
				Button,
				{
					variant: 'primary',
					onClick: confirm,
					disabled: ! selectedName,
				},
				__( 'Insert', 'joc-blockora-morph' )
			)
		)
	);
}

registerPlugin( 'joc-blockora-morph-variant-insert', {
	render: VariantInsertPicker,
	icon: brandBlockIcon( 20 ),
} );
