import { __ } from '@wordpress/i18n';
import { link, linkOff } from '@wordpress/icons';
import { useContext, useState, useEffect, useRef } from '@wordpress/element';
import { BaseControl, Tooltip, Button } from '@wordpress/components';
import { applyFilters } from '@wordpress/hooks';
import { isEqual, isEmpty } from 'lodash';
import { ColorPicker } from '@edge22/components';

import PanelArea from '../../../../components/panel-area';
import getIcon from '../../../../utils/get-icon';
import ControlsContext from '../../../../block-context';
import getDeviceType from '../../../../utils/get-device-type';
import getResponsivePlaceholder from '../../../../utils/get-responsive-placeholder';
import DimensionsControl from '../../../../components/dimensions';
import FlexControl from '../../../../components/flex-control';
import UnitControl from '../../../../components/unit-control';
import StyleDropdown from './components/style-dropdown';
import isNumeric from '../../../../utils/is-numeric';
import { useStyleIndicator, useDeviceAttributes } from '../../../../hooks';
import { getContentAttribute } from '../../../../utils/get-content-attribute';

import './editor.scss';

export default function Borders( { attributes, setAttributes, computedStyles } ) {
	const device = getDeviceType();
	const { id, blockName, supports: { borders: bordersPanel } } = useContext( ControlsContext );
	const [ deviceAttributes, setDeviceAttributes ] = useDeviceAttributes( attributes, setAttributes );
	const borderRadiusAttributes = [ 'borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomLeftRadius', 'borderBottomRightRadius' ];
	const borderAreas = [ 'borderTop', 'borderRight', 'borderBottom', 'borderLeft' ];
	const borderLabels = {
		borderTop: __( 'Top', 'generateblocks' ),
		borderRight: __( 'Right', 'generateblocks' ),
		borderBottom: __( 'Bottom', 'generateblocks' ),
		borderLeft: __( 'Left', 'generateblocks' ),
	};
	const [ sync, setSync ] = useState( false );
	const contentValue = getContentAttribute( attributes, blockName );
	const panelControls = {
		borderTopColor: false,
		borderTopStyle: false,
		borderTopWidth: false,
		borderRightColor: false,
		borderRightStyle: false,
		borderRightWidth: false,
		borderBottomColor: false,
		borderBottomStyle: false,
		borderBottomWidth: false,
		borderLeftColor: false,
		borderLeftStyle: false,
		borderLeftWidth: false,
		borderTopLeftRadius: false,
		borderTopRightRadius: false,
		borderBottomRightRadius: false,
		borderBottomLeftRadius: false,
	};
	const {
		dispatchControlGlobalStyle,
		styleSources,
		hasGlobalStyle,
		contentWasUpdated,
	} = useStyleIndicator( computedStyles, panelControls, contentValue, deviceAttributes );
	const panelRef = useRef( null );

	function getLabel( defaultLabel, rules ) {
		return applyFilters(
			'generateblocks.editor.control.label',
			defaultLabel,
			rules,
			styleSources,
			dispatchControlGlobalStyle,
			contentWasUpdated,
		);
	}

	const {
		borderTopColor = '',
		borderTopStyle = '',
		borderTopWidth = '',
		borderRightColor = '',
		borderRightStyle = '',
		borderRightWidth = '',
		borderBottomColor = '',
		borderBottomStyle = '',
		borderBottomWidth = '',
		borderLeftColor = '',
		borderLeftStyle = '',
		borderLeftWidth = '',
		borderTopLeftRadius = '',
		borderTopRightRadius = '',
		borderBottomRightRadius = '',
		borderBottomLeftRadius = '',
	} = deviceAttributes.borders;

	const labels = {
		borders: getLabel(
			__( 'Border', 'generateblocks' ),
			{
				borderTopColor,
				borderTopStyle,
				borderTopWidth,
				borderRightColor,
				borderRightStyle,
				borderRightWidth,
				borderBottomColor,
				borderBottomStyle,
				borderBottomWidth,
				borderLeftColor,
				borderLeftStyle,
				borderLeftWidth,
			}
		),
		borderRadius: getLabel(
			__( 'Border Radius', 'generateblocks' ),
			{
				borderTopLeftRadius,
				borderTopRightRadius,
				borderBottomRightRadius,
				borderBottomLeftRadius,
			}
		),
	};

	useEffect( () => {
		const allValues = borderAreas.map( ( area ) => {
			return Object.entries( deviceAttributes.borders ).reduce( ( newObject, [ key, value ] ) => {
				if ( key.startsWith( area ) && value ) {
					const newKey = key.replace( area, '' );

					newObject = {
						...newObject,
						[ newKey ]: value,
					};
				}

				return newObject;
			}, {} );
		} );

		if (
			4 === allValues.length &&
			allValues.every( ( obj ) => ! isEmpty( obj ) && isEqual( obj, allValues[ 0 ] ) )
		) {
			setSync( true );
		}
	}, [] );

	function manualSync() {
		const areasWithWidth = borderAreas.filter( ( area ) => deviceAttributes.borders[ area + 'Width' ] || isNumeric( deviceAttributes.borders[ area + 'Width' ] ) );

		if ( ! areasWithWidth.length ) {
			return;
		}

		const firstArea = areasWithWidth[ 0 ];

		const valuesToSync = Object.entries( deviceAttributes.borders ).reduce( ( newObject, [ key, value ] ) => {
			if ( key.startsWith( firstArea ) ) {
				const newKey = key.replace( firstArea, '' );
				newObject[ newKey ] = value;
			}

			return newObject;
		}, {} );

		const newDeviceAttributes = Object.entries( valuesToSync ).reduce( ( newObject, [ key, value ] ) => {
			borderAreas.forEach( ( area ) => {
				newObject[ area + key ] = value;
			} );

			return newObject;
		}, {} );

		setDeviceAttributes( newDeviceAttributes, 'borders' );
	}

	return (
		<PanelArea
			title={ __( 'Borders', 'generateblocks' ) }
			initialOpen={ false }
			icon={ getIcon( 'borders' ) }
			className="gblocks-panel-label"
			ref={ panelRef }
			hasGlobalStyle={ hasGlobalStyle }
			id={ `${ id }Borders` }
		>
			{ ( bordersPanel.borderTop || bordersPanel.borderRight || bordersPanel.borderBottom || bordersPanel.borderLeft ) &&
				<BaseControl
					label={ labels.borders }
					id={ 'gblocks-borderTop-width' }
					className="gblocks-border-row"
				>
					<Tooltip text={ !! sync ? __( 'Unlink Sides', 'generateblocks' ) : __( 'Link Sides', 'generateblocks' ) } >
						<Button
							className="components-gblocks-dimensions-control_sync"
							aria-label={ !! sync ? __( 'Unlink Sides', 'generateblocks' ) : __( 'Link Sides', 'generateblocks' ) }
							variant={ !! sync ? 'primary' : '' }
							aria-pressed={ !! sync }
							onClick={ () => {
								setSync( ! sync );

								if ( ! sync ) {
									manualSync();
								}
							} }
						>
							{ !! sync ? link : linkOff }
						</Button>
					</Tooltip>

					{ borderAreas.map( ( borderArea, areaIndex ) => {
						if ( ! bordersPanel[ borderArea ] ) {
							return null;
						}

						if ( sync && areaIndex > 0 ) {
							return null;
						}

						const iconBorderStyle = !! sync
							? 'borderAll'
							: borderArea;

						return (
							<FlexControl key={ borderArea }>
								<Tooltip text={ !! sync ? __( 'All sides', 'generateblocks' ) : borderLabels[ borderArea ] }>
									<div className={ 'gblocks-border-icon ' + iconBorderStyle } style={ { borderStyle: attributes.borders[ borderArea + 'Style' ] } }></div>
								</Tooltip>

								<UnitControl
									id={ 'gblocks-' + borderArea + '-width' }
									value={ deviceAttributes.borders[ borderArea + 'Width' ] || '' }
									placeholder={ getResponsivePlaceholder( borderArea + 'Width', attributes.borders, device ) }
									onChange={ ( value ) => {
										const newAttributes = {
											[ borderArea + 'Width' ]: value,
										};

										if ( sync ) {
											newAttributes.borderRightWidth = value;
											newAttributes.borderBottomWidth = value;
											newAttributes.borderLeftWidth = value;
										}

										if ( ! value ) {
											newAttributes[ borderArea + 'Style' ] = '';

											if ( sync ) {
												newAttributes.borderRightStyle = '';
												newAttributes.borderBottomStyle = '';
												newAttributes.borderLeftStyle = '';
											}
										} else if ( ! attributes.borders[ borderArea + 'Style' ] ) {
											newAttributes[ borderArea + 'Style' ] = 'solid';

											if ( sync ) {
												newAttributes.borderRightStyle = 'solid';
												newAttributes.borderBottomStyle = 'solid';
												newAttributes.borderLeftStyle = 'solid';
											}
										}

										setDeviceAttributes( newAttributes, 'borders' );
									} }
								/>

								<StyleDropdown
									value={ deviceAttributes.borders[ borderArea + 'Style' ] || getResponsivePlaceholder( borderArea + 'Style', attributes.borders, device ) }
									onChange={ ( value ) => {
										const newAttributes = {
											[ borderArea + 'Style' ]: value,
										};

										if ( sync ) {
											newAttributes.borderRightStyle = value;
											newAttributes.borderBottomStyle = value;
											newAttributes.borderLeftStyle = value;
										}

										setDeviceAttributes( newAttributes, 'borders' );
									} }
								/>

								{ !! bordersPanel.borderColors.length && 'Desktop' === device &&
									<div className="gblocks-border-colors">
										{ bordersPanel.borderColors.map( ( borderColor, index ) => {
											return (
												<ColorPicker
													key={ 'border' + index }
													tooltip={ borderColor?.tooltip }
													value={ attributes.borders[ borderArea + 'Color' + borderColor.state ] || '' }
													alpha={ borderColor.alpha || false }
													onChange={ ( nextBackgroundColor ) => {
														const newAttributes = {
															[ borderArea + 'Color' + borderColor.state ]: nextBackgroundColor,
														};

														if ( sync ) {
															newAttributes[ 'borderRightColor' + borderColor.state ] = nextBackgroundColor;
															newAttributes[ 'borderBottomColor' + borderColor.state ] = nextBackgroundColor;
															newAttributes[ 'borderLeftColor' + borderColor.state ] = nextBackgroundColor;
														}

														setAttributes( {
															borders: {
																...newAttributes,
															},
														} );
													} }
												/>
											);
										} ) }
									</div>
								}
							</FlexControl>
						);
					} ) }
				</BaseControl>
			}

			{ bordersPanel.borderRadius &&
				<DimensionsControl
					label={ labels.borderRadius }
					attributeNames={ borderRadiusAttributes }
					values={ deviceAttributes.borders }
					placeholders={ borderRadiusAttributes.reduce( ( o, key ) => (
						{ ...o, [ key ]: getResponsivePlaceholder( key, attributes.borders, device, '' ) }
					), {} ) }
					onChange={ ( values ) => setDeviceAttributes( values, 'borders' ) }
				/>
			}
		</PanelArea>
	);
}
