import * as React from 'react'
import {__, _x} from '@wordpress/i18n'

import {
	useContext,
	useState,
} from '@wordpress/element'

import {
	Icon,
	MenuItem,
	Modal,
	__experimentalVStack as VStack,
	CheckboxControl,
} from '@wordpress/components'

import {
	useSelect,
	useDispatch,
} from '@wordpress/data'

import {
	store as blockEditorStore,
	// @ts-expect-error
} from '@wordpress/block-editor'

import {
	store as noticesStore,
} from '@wordpress/notices'

import {
	undo as undoIcon,
} from '@wordpress/icons'

import {
	ActionInput,
} from '@ska/components'

import {
	useSkaBlocksDispatch,
} from '../../../tailwind/reducer'

import {
	InspectorControlsContext,
	type MenuItemProps,
} from '../../../tailwind/inspector-controls'

import {
	getAs,
} from '../../../supports'

import type {
	tBlockAttributes,
} from '@ska/shared'

import type {
	SelectorsValue,
} from '..'

const MoveToParentModal: React.FC<{parentClientId: string, onRequestClose: () => void}> = ({
	parentClientId,
	onRequestClose,
}) => {

	const {
		attributes,
		setAttributes,
		features,
	} = useContext(InspectorControlsContext)

	const {
		className = '',
		skaBlocksAs = {},
		skaBlocksSelectors = {},
	} = attributes

	const firstClassName = className.split(' ')[0].trim()
	const [AsElement] = getAs({skaBlocksAs})
	const hasAs = Object.keys(skaBlocksAs).length > 0 && !['div', 'span'].includes(AsElement)
	const initialSelector = firstClassName ? `[&>.${firstClassName}]` : (hasAs ? `[&>${AsElement}]` : `*`)

	const {
		createSuccessNotice,
	} = useDispatch(noticesStore)

	const parentAttributes = useSelect((select: any) => select(blockEditorStore).getBlockAttributes(parentClientId), [parentClientId])
	const {updateBlockAttributes} = useDispatch(blockEditorStore)
	const setParentAttributes = (nextAttributes: tBlockAttributes) => updateBlockAttributes(parentClientId, nextAttributes)

	const parentDispatch = useSkaBlocksDispatch(parentAttributes, setParentAttributes)
	const dispatch = useSkaBlocksDispatch(attributes, setAttributes)

	const [selector, setSelector] = useState(initialSelector)
	const usedFeatures = features.filter(({hasValue}) => hasValue)
	const [excludedFeatures, setExcludedFeatures] = useState<string[]>([])
	const selectors = Object.keys(skaBlocksSelectors)
	const [excludedSelectors, setExcludedSelectors] = useState<string[]>([])

	const onMove = () => {

		let targetSelector = selector.trim()
		if(targetSelector) {
			// Trim `:` from the right.
			while(targetSelector[targetSelector.length - 1] === ':') {
				targetSelector = targetSelector.substring(0, targetSelector.length - 1)
			}
		}

		const {
			skaBlocksSelectors: parentSkaBlocksSelectors = {},
		} = parentAttributes

		const nextSelectors = selectors.reduce((acc, cur) => {
			if(!excludedSelectors.includes(cur)) {
				acc[cur] = {
					...acc[cur],
					...skaBlocksSelectors[cur],
				}
			}
			return acc
		}, {...parentSkaBlocksSelectors[targetSelector]} as SelectorsValue)

		const keptSelectors = selectors.reduce((acc, cur) => {
			if(excludedSelectors.includes(cur)) {
				acc[cur] = {
					...skaBlocksSelectors[cur],
				}
			}
			return acc
		}, {} as SelectorsValue)

		const includedFeatures = usedFeatures.filter(({id}) => !excludedFeatures.includes(id))
		const targetAttributes = includedFeatures.reduce((acc, {id}) => {
			acc[id] = attributes[id]
			return acc
		}, {skaBlocksSelectors: nextSelectors} as tBlockAttributes)

		if(targetSelector) {
			parentDispatch.updateSelectorValue({
				selector: targetSelector,
				attributes: targetAttributes,
			})
		} else {
			parentDispatch.setAttributes(targetAttributes)
		}

		dispatch.batch([
			dispatch.actions.resetFeatures(includedFeatures.map(({id}) => id)),
			dispatch.actions.setSelectors(keptSelectors),
		])

		createSuccessNotice(__('Moved classes to parent block', 'ska-blocks'), {type: 'snackbar'})
		onRequestClose()
	}

	return (
		<Modal
			className='ska-blocks__modal ska-blocks__modal--move-to-parent'
			title={__('Move classes to parent', 'ska-blocks')}
			onRequestClose={onRequestClose}
		>
			<label
				htmlFor='ska-move-to-parent'
				className='ska-label'
			>
				{__('Selector', 'ska-blocks')}
			</label>
			<VStack spacing='4'>
				<ActionInput
					id='ska-move-to-parent'
					placeholder={__('Selector…', 'ska-blocks')}
					actionLabel={__('Move', 'ska-blocks')}
					clearLabel={_x('Clear value', 'action-input', 'ska-blocks')}
					value={selector}
					onChange={setSelector}
					onClear={() => setSelector('')}
					onSubmit={onMove}
					disabledWhenBlank={false}
				/>
				<p className='description'>{__(`Add a selector (e.g. "[&>p]") to create on the parent block or leave blank to apply this block's classes directly on the parent.`, 'ska-blocks')}</p>
				{usedFeatures.length > 0 && (
					<fieldset>
						<legend>{__('Features', 'ska-blocks')}</legend>
						<VStack>
							{usedFeatures.map(({id, label}) => (
								<CheckboxControl
									key={id}
									label={label}
									checked={!excludedFeatures.includes(id)}
									onChange={() => setExcludedFeatures(
										excludedFeatures.includes(id)
											? excludedFeatures.filter(eid => eid !== id)
											: excludedFeatures.concat(id)
									)}
									__nextHasNoMarginBottom
								/>
							))}
						</VStack>
					</fieldset>
				)}
				{selectors.length > 0 && (
					<fieldset>
						<legend>{__('Selectors', 'ska-blocks')}</legend>
						<VStack>
							{selectors.map(selector => (
								<CheckboxControl
									key={selector}
									label={selector}
									checked={!excludedSelectors.includes(selector)}
									onChange={() => setExcludedSelectors(
										excludedSelectors.includes(selector)
											? excludedSelectors.filter(s => s !== selector)
											: excludedSelectors.concat(selector)
									)}
									__nextHasNoMarginBottom
								/>
							))}
						</VStack>
					</fieldset>
				)}
			</VStack>
		</Modal>
	)
}

const MoveToParentMenuItem: React.FC<MenuItemProps> = props => {

	const {
		clientId,
		attributes,
		onClose,
	} = props

	const [isOpen, setIsOpen] = useState(false)

	const blockParents = useSelect((select: any) => select(blockEditorStore).getBlockParents(clientId), [clientId])
	const hasParent = blockParents.length > 0
	if(!hasParent) {
		return null
	}
	const parent = blockParents[blockParents.length - 1]

	const {
		skaBlocks = {},
		skaBlocksSelectors = {},
	} = attributes

	const {
		cx: tailwindClasses = '',
	} = skaBlocks

	const hasSelectors = Object.keys(skaBlocksSelectors).length > 0

	if(!tailwindClasses && !hasSelectors) {
		return null
	}

	return <>
		<MenuItem
			icon={<Icon icon={undoIcon} style={{transform: 'rotate(90deg)'}} />}
			children={__('Move classes to parent', 'ska-blocks')}
			onClick={() => {
				setIsOpen(true)
			}}
		/>
		{isOpen && (
			<MoveToParentModal
				parentClientId={parent}
				onRequestClose={() => {
					setIsOpen(false)
					onClose()
				}}
			/>
		)}
	</>
}

export default MoveToParentMenuItem
