import clsx from 'clsx';
import { __ } from '@wordpress/i18n';
import {
	DropdownMenu,
	TextControl,
	ToolbarButton,
	__experimentalToolsPanel as ToolsPanel,
	__experimentalToolsPanelItem as ToolsPanelItem,
} from '@wordpress/components';
import {
	flipHorizontal as flipHorizontalIcon,
	flipVertical as flipVerticalIcon,
	rotateRight,
} from '@wordpress/icons';
import {
	BlockControls,
	InspectorControls,
	useBlockProps,
	useBlockEditingMode,
	__experimentalUseColorProps as useColorProps,
	__experimentalUseBorderProps as useBorderProps,
	__experimentalGetSpacingClassesAndStyles as useSpacingProps,
	getDimensionsClassesAndStyles as useDimensionsProps,
} from '@wordpress/block-editor';
import { useState } from '@wordpress/element';
import { SVG, Rect, Path } from '@wordpress/primitives';
import { useSelect } from '@wordpress/data';
import { store as coreDataStore } from '@wordpress/core-data';
import { useToolsPanelDropdownMenuProps } from '../utils/hooks';
import HtmlRenderer from '../utils/html-renderer';
import { CustomInserterModal } from './components';

const IconPlaceholder = ( { className, style } ) => (
	<SVG
		xmlns="http://www.w3.org/2000/svg"
		viewBox="0 0 60 60"
		preserveAspectRatio="none"
		fill="none"
		aria-hidden="true"
		className={ clsx( 'wp-block-icon__placeholder', className ) }
		style={ style }
	>
		<Rect width="60" height="60" fill="currentColor" fillOpacity={ 0.1 } />
		<Path
			vectorEffect="non-scaling-stroke"
			stroke="currentColor"
			strokeOpacity={ 0.25 }
			d="M60 60 0 0"
		/>
	</SVG>
);

export function Edit( { attributes, setAttributes } ) {
	const { icon, ariaLabel, flipHorizontal, flipVertical, rotation } =
		attributes;

	const [ isInserterOpen, setInserterOpen ] = useState( false );

	const isContentOnlyMode = useBlockEditingMode() === 'contentOnly';

	const colorProps = useColorProps( attributes );
	// Only padding is applied to the inner SVG element, matching the front
	// end. The margin support is serialized to the block wrapper instead.
	const spacingProps = useSpacingProps( {
		style: {
			spacing: {
				padding: attributes.style?.spacing?.padding,
			},
		},
	} );
	const borderProps = useBorderProps( attributes );
	const dimensionsProps = useDimensionsProps( attributes );

	const selectedIcon = useSelect(
		( select ) => {
			const { getEntityRecord } = select( coreDataStore );
			return icon ? getEntityRecord( 'root', 'icon', icon ) : null;
		},
		[ icon ]
	);

	const iconToDisplay = selectedIcon?.content || '';

	const flipClasses = {
		'is-flip-horizontal': flipHorizontal,
		'is-flip-vertical': flipVertical,
	};

	const rotationStyle = rotation ? { rotate: `${ rotation }deg` } : {};

	const blockControls = (
		<>
			{ icon && (
				<BlockControls group="block">
					<ToolbarButton
						icon={ flipHorizontalIcon }
						label={ __( 'Flip horizontal' ) }
						isPressed={ flipHorizontal }
						onClick={ () =>
							setAttributes( {
								flipHorizontal: ! flipHorizontal,
							} )
						}
					/>
					<ToolbarButton
						icon={ flipVerticalIcon }
						label={ __( 'Flip vertical' ) }
						isPressed={ flipVertical }
						onClick={ () =>
							setAttributes( {
								flipVertical: ! flipVertical,
							} )
						}
					/>
					<ToolbarButton
						icon={ rotateRight }
						label={ __( 'Rotate' ) }
						onClick={ () =>
							setAttributes( {
								rotation: ( ( rotation || 0 ) + 90 ) % 360,
							} )
						}
					/>
				</BlockControls>
			) }
			<BlockControls group="other">
				<ToolbarButton
					onClick={ () => {
						setInserterOpen( true );
					} }
				>
					{ icon ? __( 'Replace' ) : __( 'Choose icon' ) }
				</ToolbarButton>
				{ isContentOnlyMode && icon && (
					// Add some extra controls for content attributes when content only mode is active.
					// With content only mode active, the inspector is hidden, so users need another way
					// to edit these attributes.
					<DropdownMenu
						icon=""
						toggleProps={ {
							as: ToolbarButton,
						} }
						popoverProps={ {
							className: 'is-alternate',
						} }
						text={ __( 'Label' ) }
					>
						{ () => (
							<TextControl
								className="wp-block-icon__toolbar-content"
								label={ __( 'Label' ) }
								value={ ariaLabel || '' }
								onChange={ ( value ) =>
									setAttributes( {
										ariaLabel: value,
									} )
								}
								help={ __(
									'Briefly describe the icon to help screen reader users. Leave blank for decorative icons.'
								) }
							/>
						) }
					</DropdownMenu>
				) }
			</BlockControls>
		</>
	);
	const dropdownMenuProps = useToolsPanelDropdownMenuProps();
	const inspectorControls = icon && (
		<>
			<InspectorControls group="settings">
				<ToolsPanel
					label={ __( 'Settings' ) }
					resetAll={ () =>
						setAttributes( {
							ariaLabel: undefined,
						} )
					}
					dropdownMenuProps={ dropdownMenuProps }
				>
					<ToolsPanelItem
						label={ __( 'Label' ) }
						isShownByDefault
						hasValue={ () => !! ariaLabel }
						onDeselect={ () =>
							setAttributes( { ariaLabel: undefined } )
						}
					>
						<TextControl
							label={ __( 'Label' ) }
							help={ __(
								'Briefly describe the icon to help screen reader users. Leave blank for decorative icons.'
							) }
							value={ ariaLabel || '' }
							onChange={ ( value ) =>
								setAttributes( { ariaLabel: value } )
							}
						/>
					</ToolsPanelItem>
				</ToolsPanel>
			</InspectorControls>
		</>
	);

	return (
		<>
			{ blockControls }
			{ inspectorControls }
			<div { ...useBlockProps() }>
				{ iconToDisplay ? (
					<HtmlRenderer
						html={ iconToDisplay }
						wrapperProps={ {
							className: clsx(
								colorProps.className,
								borderProps.className,
								spacingProps.className,
								dimensionsProps.className,
								flipClasses
							),
							style: {
								...colorProps.style,
								...borderProps.style,
								...spacingProps.style,
								...dimensionsProps.style,
								...rotationStyle,
							},
						} }
					/>
				) : (
					<IconPlaceholder
						className={ clsx(
							borderProps.className,
							spacingProps.className,
							dimensionsProps.className,
							flipClasses
						) }
						style={ {
							...borderProps.style,
							...spacingProps.style,
							...dimensionsProps.style,
							...rotationStyle,
							height: 'auto',
						} }
					/>
				) }
			</div>
			{ isInserterOpen && (
				<CustomInserterModal
					onClose={ () => setInserterOpen( false ) }
					value={ attributes.icon }
					onChange={ ( name ) => {
						setAttributes( { icon: name } );
						setInserterOpen( false );
					} }
				/>
			) }
		</>
	);
}

export default Edit;
