/**
 * External dependencies.
 */
import { InspectorControls } from '@wordpress/block-editor';
import {
	__experimentalToolsPanel as ToolsPanel,
	__experimentalToolsPanelItem as ToolsPanelItem,
	__experimentalVStack as VStack,
	ToggleControl,
} from '@wordpress/components';
import { useDispatch } from '@wordpress/data';
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies.
 */
import DynamicImage from '@spectra-pro-extensions/dynamic-content/components/DynamicImage';
import { DynamicContentProvider } from '@spectra-pro-extensions/dynamic-content/context/DynamicContentContext';
import { getDynamicContent } from '@spectra-pro-extensions/dynamic-content/utils/helpers';
import DynamicLink from '@spectra-pro-extensions/dynamic-content/components/DynamicLink';

/**
 * Extends the core/image block with dynamic image and link controls.
 *
 * Adds inspector controls to toggle dynamic image and link support, manage dynamic
 * content settings, and handle attribute updates for the core/image block. Supports
 * switching between static and dynamic images and links.
 *
 * @since x.x.x
 *
 * @param {Object}   props               - The component props.
 * @param {string}   props.blockName     - The name of the block (e.g., 'core/image').
 * @param {Object}   props.attributes    - The block's attributes.
 * @param {Function} props.setAttributes - Function to update block attributes.
 * @return {Element} The inspector controls for dynamic image and link settings.
 */
const CoreImageWithDynamicImage = ( props ) => {
	// Destructure only what we need from props
	const { blockName, attributes, setAttributes, clientId } = props;

	const { spectraProEnableDynamicImage, spectraProDynamicImage, spectraProEnableDynamicLink, href } = attributes;

	const { __unstableMarkNextChangeAsNotPersistent, updateBlockAttributes } = useDispatch( 'core/block-editor' );

	/**
	 * Handles toggling the dynamic image feature.
	 *
	 * Updates block attributes to enable or disable dynamic images, fetching dynamic
	 * content when enabling or restoring static image when disabling.
	 *
	 * @param {boolean} newValue - The new toggle state.
	 */
	const handleImageToggle = async ( newValue ) => {
		setAttributes( {
			spectraProEnableDynamicImage: newValue,
		} );

		if ( newValue && spectraProDynamicImage ) {
			// Re-enable dynamic image and fetch content if settings exist.
			const dynamicImage = await getDynamicContent( spectraProDynamicImage, 'image' );

			if ( dynamicImage?.url ) {
				/**
				 * Use requestAnimationFrame to defer the attribute update until the next browser paint cycle.
				 * This ensures the UI is updated smoothly and prevents potential rendering conflicts.
				 *
				 * @see https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
				 */
				requestAnimationFrame( () => {
					/**
					 * Mark the next change as not persistent to prevent it from being saved to the block's undo history.
					 * This is important for dynamic content as these changes are visual updates in the editor
					 * rather than actual content edits that should be tracked in the undo stack.
					 */
					__unstableMarkNextChangeAsNotPersistent();
					updateBlockAttributes( clientId, {
						url: dynamicImage.url,
						id: dynamicImage?.id,
					} );
				} );
			}
		}
	};

	/**
	 * Handles toggling the dynamic link feature.
	 *
	 * Updates block attributes to enable or disable dynamic links, setting a placeholder
	 * href when enabling or clearing it when disabling if applicable.
	 */
	const handleLinkToggle = () => {
		const newValue = ! spectraProEnableDynamicLink;

		const newAttributes = {
			spectraProEnableDynamicLink: newValue,
		};

		if ( newValue ) {
			// If enabling and href is empty, set default dynamic href.
			if ( ! href ) {
				newAttributes.href = 'spectra-dynamic-link';
			}
		} else {
			// If disabling, remove dynamic href only if it was the placeholder.
			newAttributes.href = href === 'spectra-dynamic-link' ? '' : href;
		}

		setAttributes( newAttributes );
	};

	/**
	 * Resets all dynamic content settings.
	 *
	 * Disables dynamic image and link support and clears placeholder href if present.
	 */
	const resetAll = () => {
		setAttributes( {
			spectraProEnableDynamicImage: false,
			spectraProEnableDynamicLink: false,
		} );

		// Clear placeholder href if it was set.
		if ( 'spectra-dynamic-link' === href ) {
			setAttributes( { href: '' } );
		}
	};

	return (
		<InspectorControls>
			{ /* ToolsPanel for dynamic content settings.
				- Provides controls to toggle dynamic image and link support.
				- Default values:
				- Dynamic Image spectraProEnableDynamicImage: false
				- Dynamic Link spectraProEnableDynamicLink: false
				- Includes a "Reset All" option to restore default values.
			*/ }
			<ToolsPanel label={ __( 'Spectra Dynamic Content', 'spectra-pro' ) } resetAll={ resetAll }>
				{ /* This ToolsPanelItem will reset when the following condition is met:
					- The "spectraProEnableDynamicImage" attribute is set. Default: false.
				*/ }
				<ToolsPanelItem
					label={ __( 'Dynamic Content', 'spectra-pro' ) }
					isShownByDefault
					hasValue={ () => !! spectraProEnableDynamicImage }
					onDeselect={ () => setAttributes( { spectraProEnableDynamicImage: false } ) }
				>
					<VStack spacing={ 4 }>
						<ToggleControl
							label={ __( 'Dynamic Image', 'spectra-pro' ) }
							checked={ spectraProEnableDynamicImage }
							onChange={ handleImageToggle }
						/>

						{ spectraProEnableDynamicImage && (
							<DynamicContentProvider>
								<DynamicImage
									type="image"
									blockName={ blockName }
									attributes={ attributes }
									setAttributes={ setAttributes }
									clientId={ clientId }
								/>
							</DynamicContentProvider>
						) }
					</VStack>
				</ToolsPanelItem>

				{ /* This ToolsPanelItem will reset when the following condition is met:
					- The "spectraProEnableDynamicLink" attribute is set. Default: false.
				*/ }
				<ToolsPanelItem
					label={ __( 'Dynamic Link', 'spectra-pro' ) }
					isShownByDefault
					hasValue={ () => !! spectraProEnableDynamicLink }
					onDeselect={ () => setAttributes( { spectraProEnableDynamicLink: false } ) }
				>
					<VStack spacing={ 4 }>
						<ToggleControl
							label={ __( 'Dynamic Link', 'spectra-pro' ) }
							checked={ spectraProEnableDynamicLink }
							onChange={ handleLinkToggle }
						/>
						{ spectraProEnableDynamicLink && (
							<DynamicContentProvider>
								<DynamicLink attributes={ attributes } setAttributes={ setAttributes } type="image" />
							</DynamicContentProvider>
						) }
					</VStack>
				</ToolsPanelItem>
			</ToolsPanel>
		</InspectorControls>
	);
};

export default CoreImageWithDynamicImage;
