/**
 * External dependencies
 */
import { InspectorControls, useSettings } from '@wordpress/block-editor';
import {
	__experimentalToggleGroupControl as ToggleGroupControl,
	__experimentalToolsPanel as ToolsPanel,
	__experimentalToolsPanelItem as ToolsPanelItem,
	__experimentalToggleGroupControlOption as ToggleGroupControlOption,
	__experimentalUnitControl as UnitControl,
	__experimentalUseCustomUnits as useCustomUnits,
	AnglePickerControl,
	ToggleControl,
	__experimentalVStack as VStack,
} from '@wordpress/components';
import { memo } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import IconPicker from '@spectra-components/icon-picker';
import InspectorColor from '@spectra-components/inspector-color';

/**
 * Element Sub-settings: General settings, but based on the parent block.
 *
 * @param {Object} props The element props.
 * @since x.x.x
 * @return {Element} The rendered block settings.
 */
const ConditionalBlockSettings = memo( ( props ) => {
	// Destructure the required props.
	const {
		clientId,
		setAttributes,
		attributes: { showText, icon, iconPosition = 'after', flipForRTL, rotation },
	} = props;

	const resetAllSettings = () => {
		setAttributes( {
			showText: true,
			icon: undefined,
			iconPosition: 'after',
			flipForRTL: false,
			rotation: undefined,
		} );
	};

	// Render the settings.
	return (
		<>
			<InspectorControls group="settings">
				<ToolsPanel
					label={ __( 'Next', 'spectra-pro' ) }
					resetAll={ resetAllSettings }
					panelId={ clientId }
				>
					<ToggleControl
						checked={ showText }
						label={ __( 'Show Text', 'spectra-pro' ) }
						disabled={ ! icon }
						onChange={ () =>
							setAttributes( { showText: ! showText } )
						}
					/>
					<ToolsPanelItem
						hasValue={ () => !! icon }
						label={ __( 'Icon', 'spectra-pro' ) }
						onDeselect={ () =>
							setAttributes( { icon: undefined } )
						}
						resetAllFilter={ () => ( {
							icon: undefined,
						} ) }
						isShownByDefault
						panelId={ clientId }
					>
						<VStack spacing={ 4 }>
							<IconPicker
								value={ icon }
								onChange={ ( value ) => {
									setAttributes( { icon: value } );

									if ( ! value && ! showText ) {
										setAttributes( { showText: true } );
									}
								} }
							/>
							{ icon && (
								<ToggleControl
									__nextHasNoMarginBottom
									checked={ flipForRTL }
									label={ __(
										'Flip Icon for Right-To-Left',
										'spectra-pro'
									) }
									onChange={ () =>
										setAttributes( {
											flipForRTL: ! flipForRTL,
										} )
									}
									help={ __(
										"Enable this for your RTL visitors if you are using a direction-specific icon. Like 'Arrow Right', 'Chart Line', etc. ",
										'spectra-pro'
									) }
								/>
							) }
						</VStack>
					</ToolsPanelItem>
					{/* This tool panel item will require reset when any of these conditions are met:
					- The rotation attribute is set. Default: undefined.
					*/}
					{ icon && (
						<ToolsPanelItem
							hasValue={ () => !! rotation }
							label={ __( 'Rotation', 'spectra-pro' ) }
							onDeselect={ () => setAttributes( { rotation: undefined } ) }
							resetAllFilter={ () => ( {
								rotation: undefined,
							} ) }
							panelId={ clientId }
						>
							<AnglePickerControl
								label={ __( 'Rotation', 'spectra-pro' ) }
								onChange={ ( value ) => {
									setAttributes( { rotation: value } );
								} }
								value={ rotation }
							/>
						</ToolsPanelItem>
					) }
					{ icon && (
						<ToolsPanelItem
							hasValue={ () => !! iconPosition }
							label={ __( 'Position', 'spectra-pro' ) }
							onDeselect={ () =>
								setAttributes( { iconPosition: undefined } )
							}
							resetAllFilter={ () => ( {
								iconPosition: undefined,
							} ) }
							isShownByDefault
							panelId={ clientId }
						>
							<ToggleGroupControl
								__nextHasNoMarginBottom
								__next40pxDefaultSize
								label={ __( 'Position', 'spectra-pro' ) }
								value={ iconPosition }
								onChange={ ( value ) =>
									setAttributes( { iconPosition: value } )
								}
								isBlock
							>
								<ToggleGroupControlOption
									value="before"
									label="Left"
								/>
								<ToggleGroupControlOption
									value="after"
									label="Right"
								/>
							</ToggleGroupControl>
						</ToolsPanelItem>
					) }
				</ToolsPanel>
			</InspectorControls>
		</>
	);
} );

/**
 * Element Sub-settings: Settings that are injected into Core's Color panel.
 *
 * @param {Object} props The element props.
 * @since x.x.x
 * @return {Element} The rendered block settings.
 */
const ColorSettings = memo( ( props ) => {
	// Destructure the required props.
	const {
		clientId,
		setAttributes,
		attributes: {
			textColorHover,
			backgroundColorHover,
			iconColor,
			iconColorHover,
			backgroundGradientHover,
		},
	} = props;

	return (
		<InspectorColor
			settings={ [
				{
					colorValue: textColorHover,
					label: __( 'Text Hover', 'spectra-pro' ),
					onColorChange: ( value ) =>
						setAttributes( { textColorHover: value } ),
					resetAllFilter: () =>
						setAttributes( { textColorHover: undefined } ),
				},
				{
					colorValue: iconColor,
					label: __( 'Icon', 'spectra-pro' ),
					onColorChange: ( value ) =>
						setAttributes( { iconColor: value } ),
					resetAllFilter: () =>
						setAttributes( { iconColor: undefined } ),
				},
				{
					colorValue: iconColorHover,
					label: __( 'Icon Hover', 'spectra-pro' ),
					onColorChange: ( value ) =>
						setAttributes( { iconColorHover: value } ),
					resetAllFilter: () =>
						setAttributes( { iconColorHover: undefined } ),
				},
				{
					colorValue: backgroundColorHover,
					gradientValue: backgroundGradientHover,
					label: __( 'Background Hover', 'spectra-pro' ),
					onColorChange: ( value ) =>
						setAttributes( { backgroundColorHover: value } ),
					onGradientChange: ( value ) =>
						setAttributes( { backgroundGradientHover: value } ),
					resetAllFilter: () =>
						setAttributes( { backgroundColorHover: undefined } ),
				},
			] }
			panelId={ clientId }
		/>
	);
} );

/**
 * Element Sub-settings: Settings that are injected into Core's Dimensions panel.
 *
 * @param {Object} props The element props.
 * @since x.x.x
 * @return {Element} The rendered block settings.
 */
const IconStyleSettings = memo( ( props ) => {
	// Destructure the requierd props.
	const {
		clientId,
		setAttributes,
		attributes: { size, gap },
	} = props;

	// Fetch spacing units, fallback to default
	const [ availableUnits ] = useSettings( 'spacing.units' ) || [];
	const units = useCustomUnits( {
		availableUnits: availableUnits.length
			? availableUnits
			: [ 'px', '%', 'vw', 'em', 'rem' ],
	} );

	return (
		<>
			<InspectorControls group="dimensions">
				<ToolsPanelItem
					hasValue={ () => !! size }
					label={ __( 'Icon size', 'spectra-pro' ) }
					onDeselect={ () => setAttributes( { size: undefined } ) }
					resetAllFilter={ () => ( {
						size: undefined,
					} ) }
					isShownByDefault
					panelId={ clientId }
				>
					<UnitControl
						__next40pxDefaultSize
						label={ __( 'Icon size', 'spectra-pro' ) }
						labelPosition="top"
						value={ size }
						min={ 0 }
						onChange={ ( value ) =>
							setAttributes( { size: value } )
						}
						units={ units }
					/>
				</ToolsPanelItem>
				<ToolsPanelItem
					hasValue={ () => !! gap }
					label={ __( 'Text-Icon Gap', 'spectra-pro' ) }
					onDeselect={ () => setAttributes( { gap: undefined } ) }
					resetAllFilter={ () => ( {
						gap: undefined,
					} ) }
					isShownByDefault
					panelId={ clientId }
				>
					<UnitControl
						__next40pxDefaultSize
						label={ __( 'Text-Icon Gap', 'spectra-pro' ) }
						labelPosition="top"
						value={ gap }
						min={ 0 }
						onChange={ ( value ) =>
							setAttributes( { gap: value } )
						}
						units={ units }
					/>
				</ToolsPanelItem>
			</InspectorControls>
		</>
	);
} );

/**
 * The Editor settings for this block.
 *
 * @param {Object} props The element props.
 * @since x.x.x
 * @return {Element} The rendered settings.
 */
const Settings = ( props ) => {
	const {
		attributes: { icon },
	} = props;

	return (
		<>
			{ icon && <IconStyleSettings { ...{ ...props } } /> }
			<ConditionalBlockSettings { ...{ ...props } } />
			<ColorSettings { ...{ ...props } } />
		</>
	);
};

export default memo( Settings );
