import { useState, useMemo, useRef } from '@wordpress/element';
import { ImagePlaceholder } from './ImagePlaceholder.jsx';
import { useDispatch } from '@wordpress/data';
import { store as blockEditorStore } from '@wordpress/block-editor';
import { isURL } from '@wordpress/url';

export function Image( {
	elementAttributes,
	temporaryURL,
	onSelectImage,
	onSelectURL,
	onUploadError,
	dynamicTagValue,
	isSelected,
	clientId,
	linkHtmlAttributes,
	attributes,
} ) {
	const imageRef = useRef();
	const [
		{ loadedNaturalWidth, loadedNaturalHeight },
		setLoadedNaturalSize,
	] = useState( {} );
	const { selectBlock } = useDispatch( blockEditorStore );

	// Get naturalWidth and naturalHeight from image ref, and fall back to loaded natural
	// width and height. This resolves an issue in Safari where the loaded natural
	// witdth and height is otherwise lost when switching between alignments.
	// See: https://github.com/WordPress/gutenberg/pull/37210.
	const { naturalWidth, naturalHeight } = useMemo( () => {
		return {
			naturalWidth:
				imageRef.current?.naturalWidth ||
				loadedNaturalWidth ||
				undefined,
			naturalHeight:
				imageRef.current?.naturalHeight ||
				loadedNaturalHeight ||
				undefined,
		};
	}, [
		loadedNaturalWidth,
		loadedNaturalHeight,
		imageRef.current?.complete,
	] );

	const imageSrc = useMemo( () => {
		if ( dynamicTagValue?.[ 0 ]?.replacement && isURL( dynamicTagValue?.[ 0 ]?.replacement ) ) {
			return dynamicTagValue?.[ 0 ]?.replacement;
		}

		if ( temporaryURL ) {
			return temporaryURL;
		}

		if ( elementAttributes?.src ) {
			if ( elementAttributes?.src.startsWith( '{{' ) ) {
				return generateblocksBlockMedia.squarePlaceholder;
			}

			return elementAttributes.src;
		}
	}, [ dynamicTagValue, temporaryURL, elementAttributes?.src ] );

	/* eslint-disable jsx-a11y/alt-text */
	// The alt tag below is added via elementAttributes.

	/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
	// The img element below is interactive if it's not selected.
	// This allows us to not render the surrounding `<div>` with the `blockProps`
	// unless the image is selected.

	/* eslint-disable jsx-a11y/anchor-is-valid */
	// We disable the anchor in the editor only.

	const image = (
		<>
			<img
				width={ naturalWidth }
				height={ naturalHeight }
				{ ...elementAttributes }
				src={ imageSrc }
				ref={ imageRef }
				onLoad={ ( event ) => {
					setLoadedNaturalSize( {
						loadedNaturalWidth: event.target?.naturalWidth,
						loadedNaturalHeight: event.target?.naturalHeight,
					} );
				} }
				onClick={ () => {
					if ( isSelected ) {
						return;
					}

					selectBlock( clientId );
				} }
				onKeyDown={ () => {
					if ( isSelected ) {
						return;
					}

					selectBlock( clientId );
				} }
				role={ ! isSelected ? 'button' : undefined }
				tabIndex={ ! isSelected ? 0 : undefined }
			/>
		</>
	);

	return (
		<>
			{ ( !! temporaryURL || !! elementAttributes?.src ) ? (
				<>
					{ linkHtmlAttributes.href ? (
						<a
							{ ...linkHtmlAttributes }
							href="#"
						>
							{ image }
						</a>
					) : (
						image
					) }
				</>
			) : (
				<ImagePlaceholder
					onSelectImage={ onSelectImage }
					onSelectURL={ onSelectURL }
					onUploadError={ onUploadError }
					uniqueId={ attributes?.uniqueId ?? '' }
				/>
			) }
		</>
	);

	/* eslint-enable jsx-a11y/alt-text */
	/* eslint-enable jsx-a11y/no-noninteractive-element-interactions */
	/* eslint-enable jsx-a11y/anchor-is-valid */
}