/* eslint-disable @wordpress/no-unsafe-wp-apis */

/**
 * External dependencies
 */
import { ComponentType } from 'react';
import { WP_REST_API_Category } from 'wp-types';
import { __ } from '@wordpress/i18n';
import {
	InspectorControls as GutenbergInspectorControls,
	__experimentalPanelColorGradientSettings as PanelColorGradientSettings,
	__experimentalUseGradient as useGradient,
} from '@wordpress/block-editor';
import {
	FocalPointPicker,
	PanelBody,
	RangeControl,
	ToggleControl,
	__experimentalToggleGroupControl as ToggleGroupControl,
	__experimentalToggleGroupControlOption as ToggleGroupControlOption,
	TextareaControl,
	ExternalLink,
} from '@wordpress/components';
import { LooselyMustHave, ProductResponseItem } from '@woocommerce/types';

/**
 * Internal dependencies
 */
import { useBackgroundImage } from './use-background-image';
import { BLOCK_NAMES } from './constants';
import { FeaturedItemRequiredAttributes } from './with-featured-item';
import { EditorBlock, ImageFit } from './types';

type InspectorControlRequiredKeys =
	| 'dimRatio'
	| 'focalPoint'
	| 'hasParallax'
	| 'imageFit'
	| 'isRepeated'
	| 'overlayColor'
	| 'overlayGradient'
	| 'showDesc';

interface InspectorControlsRequiredAttributes
	extends LooselyMustHave<
		FeaturedItemRequiredAttributes,
		InspectorControlRequiredKeys
	> {
	alt: string;
	backgroundImageSrc: string;
	contentPanel: JSX.Element | undefined;
}

interface InspectorControlsProps extends InspectorControlsRequiredAttributes {
	setAttributes: (
		attrs: Partial< InspectorControlsRequiredAttributes >
	) => void;
	// Gutenberg doesn't provide some types, so we have to hard-code them here
	setGradient: ( newGradientValue: string ) => void;
}

interface WithInspectorControlsRequiredProps< T > {
	attributes: InspectorControlsRequiredAttributes &
		EditorBlock< T >[ 'attributes' ];
	setAttributes: InspectorControlsProps[ 'setAttributes' ];
}

interface WithInspectorControlsCategoryProps< T >
	extends WithInspectorControlsRequiredProps< T > {
	category: WP_REST_API_Category;
	product: never;
}

interface WithInspectorControlsProductProps< T >
	extends WithInspectorControlsRequiredProps< T > {
	category: never;
	product: ProductResponseItem;
	showPrice: boolean;
}

type WithInspectorControlsProps< T extends EditorBlock< T > > =
	| ( T & WithInspectorControlsCategoryProps< T > )
	| ( T & WithInspectorControlsProductProps< T > );

export const InspectorControls = ( {
	alt,
	backgroundImageSrc,
	contentPanel,
	dimRatio,
	focalPoint,
	hasParallax,
	imageFit,
	isRepeated,
	overlayColor,
	overlayGradient,
	setAttributes,
	setGradient,
	showDesc,
}: InspectorControlsProps ) => {
	// FocalPointPicker was introduced in Gutenberg 5.0 (WordPress 5.2),
	// so we need to check if it exists before using it.
	const focalPointPickerExists = typeof FocalPointPicker === 'function';

	const isImgElement = ! isRepeated && ! hasParallax;

	return (
		<GutenbergInspectorControls key="inspector">
			<PanelBody
				title={ __( 'Content', 'woo-gutenberg-products-block' ) }
			>
				<ToggleControl
					label={ __(
						'Show description',
						'woo-gutenberg-products-block'
					) }
					checked={ showDesc }
					onChange={ () => setAttributes( { showDesc: ! showDesc } ) }
				/>
				{ contentPanel }
			</PanelBody>
			{ !! backgroundImageSrc && (
				<>
					{ focalPointPickerExists && (
						<PanelBody
							title={ __(
								'Media settings',
								'woo-gutenberg-products-block'
							) }
						>
							<ToggleControl
								label={ __(
									'Fixed background',
									'woo-gutenberg-products-block'
								) }
								checked={ hasParallax }
								onChange={ () => {
									setAttributes( {
										hasParallax: ! hasParallax,
									} );
								} }
							/>
							<ToggleControl
								label={ __(
									'Repeated background',
									'woo-gutenberg-products-block'
								) }
								checked={ isRepeated }
								onChange={ () => {
									setAttributes( {
										isRepeated: ! isRepeated,
									} );
								} }
							/>
							{ ! isRepeated && (
								<ToggleGroupControl
									help={
										<>
											<p>
												{ __(
													'Choose “Cover” if you want the image to scale automatically to always fit its container.',
													'woo-gutenberg-products-block'
												) }
											</p>
											<p>
												{ __(
													'Note: by choosing “Cover” you will lose the ability to freely move the focal point precisely.',
													'woo-gutenberg-products-block'
												) }
											</p>
										</>
									}
									label={ __(
										'Image fit',
										'woo-gutenberg-products-block'
									) }
									value={ imageFit }
									onChange={ ( value: ImageFit ) =>
										setAttributes( {
											imageFit: value,
										} )
									}
								>
									<ToggleGroupControlOption
										label={ __(
											'None',
											'woo-gutenberg-products-block'
										) }
										value="none"
									/>
									<ToggleGroupControlOption
										/* translators: "Cover" is a verb that indicates an image covering the entire container. */
										label={ __(
											'Cover',
											'woo-gutenberg-products-block'
										) }
										value="cover"
									/>
								</ToggleGroupControl>
							) }
							<FocalPointPicker
								label={ __(
									'Focal Point Picker',
									'woo-gutenberg-products-block'
								) }
								url={ backgroundImageSrc }
								value={ focalPoint }
								onChange={ ( value ) =>
									setAttributes( {
										focalPoint: value,
									} )
								}
							/>
							{ isImgElement && (
								<TextareaControl
									label={ __(
										'Alt text (alternative text)',
										'woo-gutenberg-products-block'
									) }
									value={ alt }
									onChange={ ( value: string ) => {
										setAttributes( { alt: value } );
									} }
									help={
										<>
											<ExternalLink href="https://www.w3.org/WAI/tutorials/images/decision-tree">
												{ __(
													'Describe the purpose of the image',
													'woo-gutenberg-products-block'
												) }
											</ExternalLink>
										</>
									}
								/>
							) }
						</PanelBody>
					) }
					<PanelColorGradientSettings
						__experimentalHasMultipleOrigins
						__experimentalIsRenderedInSidebar
						title={ __(
							'Overlay',
							'woo-gutenberg-products-block'
						) }
						initialOpen={ true }
						settings={ [
							{
								colorValue: overlayColor,
								gradientValue: overlayGradient,
								onColorChange: ( value: string ) =>
									setAttributes( { overlayColor: value } ),
								onGradientChange: ( value: string ) => {
									setGradient( value );
									setAttributes( {
										overlayGradient: value,
									} );
								},
								label: __(
									'Color',
									'woo-gutenberg-products-block'
								),
							},
						] }
					>
						<RangeControl
							label={ __(
								'Opacity',
								'woo-gutenberg-products-block'
							) }
							value={ dimRatio }
							onChange={ ( value ) =>
								setAttributes( { dimRatio: value as number } )
							}
							min={ 0 }
							max={ 100 }
							step={ 10 }
							required
						/>
					</PanelColorGradientSettings>
				</>
			) }
		</GutenbergInspectorControls>
	);
};

export const withInspectorControls = < T extends EditorBlock< T > >(
	Component: ComponentType< T >
) => ( props: WithInspectorControlsProps< T > ) => {
	const { attributes, name, setAttributes } = props;
	const {
		alt,
		dimRatio,
		focalPoint,
		hasParallax,
		isRepeated,
		imageFit,
		mediaId,
		mediaSrc,
		overlayColor,
		overlayGradient,
		showDesc,
		showPrice,
	} = attributes;

	const item =
		name === BLOCK_NAMES.featuredProduct ? props.product : props.category;

	const { setGradient } = useGradient( {
		gradientAttribute: 'overlayGradient',
		customGradientAttribute: 'overlayGradient',
	} );
	const { backgroundImageSrc } = useBackgroundImage( {
		item,
		mediaId,
		mediaSrc,
		blockName: name,
	} );

	const contentPanel =
		name === BLOCK_NAMES.featuredProduct ? (
			<ToggleControl
				label={ __( 'Show price', 'woo-gutenberg-products-block' ) }
				checked={ showPrice }
				onChange={ () =>
					setAttributes( {
						showPrice: ! showPrice,
					} )
				}
			/>
		) : undefined;

	return (
		<>
			<InspectorControls
				alt={ alt }
				backgroundImageSrc={ backgroundImageSrc }
				contentPanel={ contentPanel }
				dimRatio={ dimRatio }
				focalPoint={ focalPoint }
				hasParallax={ hasParallax }
				isRepeated={ isRepeated }
				imageFit={ imageFit }
				overlayColor={ overlayColor }
				overlayGradient={ overlayGradient }
				setAttributes={ setAttributes }
				setGradient={ setGradient }
				showDesc={ showDesc }
			/>
			<Component { ...props } />
		</>
	);
};
