import { useCallback } from '@wordpress/element';
import { getEnabledBreakpoints, getInheritedValue } from './breakpoints';

export const useResponsiveValue = (
	attributes,
	setAttributes,
	baseName,
	options = {}
) => {
	const {
		hoverSuffix = '',
		valueKey = '',
		unitKey = 'Unit',
		defaultUnit = 'px',
	} = options;

	const enabledBreakpoints = getEnabledBreakpoints();

	const getAttrName = ( device, suffix = '' ) => {
		const deviceUpper = device.toUpperCase();
		return `${ baseName }${ deviceUpper }${ hoverSuffix }${ suffix }`;
	};

	const getValue = useCallback(
		( device ) => {
			const attrName = getAttrName( device, valueKey );
			return attributes[ attrName ];
		},
		[ attributes, baseName, hoverSuffix, valueKey ]
	);

	const getUnit = useCallback(
		( device ) => {
			const attrName = getAttrName( device, unitKey );
			return attributes[ attrName ] || defaultUnit;
		},
		[ attributes, baseName, hoverSuffix, unitKey, defaultUnit ]
	);

	const getCustomValue = useCallback(
		( device ) => {
			const attrName = `custom${
				baseName.charAt( 0 ).toUpperCase() + baseName.slice( 1 )
			}${ device.toUpperCase() }${ hoverSuffix }`;
			return attributes[ attrName ];
		},
		[ attributes, baseName, hoverSuffix ]
	);

	const getInheritedValueForDevice = useCallback(
		( device ) => {
			const values = {};
			enabledBreakpoints.forEach( ( bp ) => {
				values[ bp ] = getValue( bp );
			} );
			return getInheritedValue( values, device );
		},
		[ enabledBreakpoints, getValue ]
	);

	const getEffectiveValue = useCallback(
		( device ) => {
			const directValue = getValue( device );
			if (
				directValue !== undefined &&
				directValue !== '' &&
				directValue !== null
			) {
				return directValue;
			}
			return getInheritedValueForDevice( device );
		},
		[ getValue, getInheritedValueForDevice ]
	);

	const setValue = useCallback(
		( device, value, responsiveEnabled = true ) => {
			if ( ! responsiveEnabled ) {
				const updates = {};
				enabledBreakpoints.forEach( ( bp ) => {
					updates[ getAttrName( bp, valueKey ) ] = value;
				} );
				setAttributes( updates );
			} else {
				setAttributes( { [ getAttrName( device, valueKey ) ]: value } );
			}
		},
		[ setAttributes, enabledBreakpoints, baseName, hoverSuffix, valueKey ]
	);

	const setUnit = useCallback(
		( device, value, responsiveEnabled = true ) => {
			if ( ! responsiveEnabled ) {
				const updates = {};
				enabledBreakpoints.forEach( ( bp ) => {
					updates[ getAttrName( bp, unitKey ) ] = value;
				} );
				setAttributes( updates );
			} else {
				setAttributes( { [ getAttrName( device, unitKey ) ]: value } );
			}
		},
		[ setAttributes, enabledBreakpoints, baseName, hoverSuffix, unitKey ]
	);

	const setCustomValue = useCallback(
		( device, value, responsiveEnabled = true ) => {
			const getCustomAttrName = ( bp ) =>
				`custom${
					baseName.charAt( 0 ).toUpperCase() + baseName.slice( 1 )
				}${ bp.toUpperCase() }${ hoverSuffix }`;

			if ( ! responsiveEnabled ) {
				const updates = {};
				enabledBreakpoints.forEach( ( bp ) => {
					updates[ getCustomAttrName( bp ) ] = value;
				} );
				setAttributes( updates );
			} else {
				setAttributes( { [ getCustomAttrName( device ) ]: value } );
			}
		},
		[ setAttributes, enabledBreakpoints, baseName, hoverSuffix ]
	);

	const syncFromPC = useCallback( () => {
		const pcValue = getValue( 'pc' );
		const pcUnit = getUnit( 'pc' );
		const pcCustom = getCustomValue( 'pc' );

		const updates = {};
		enabledBreakpoints.forEach( ( bp ) => {
			if ( bp !== 'pc' ) {
				updates[ getAttrName( bp, valueKey ) ] = pcValue;
				updates[ getAttrName( bp, unitKey ) ] = pcUnit;
				const customAttrName = `custom${
					baseName.charAt( 0 ).toUpperCase() + baseName.slice( 1 )
				}${ bp.toUpperCase() }${ hoverSuffix }`;
				updates[ customAttrName ] = pcCustom;
			}
		} );
		setAttributes( updates );
	}, [
		enabledBreakpoints,
		getValue,
		getUnit,
		getCustomValue,
		setAttributes,
		baseName,
		hoverSuffix,
		valueKey,
		unitKey,
	] );

	return {
		getValue,
		getUnit,
		getCustomValue,
		getEffectiveValue,
		getInheritedValueForDevice,
		setValue,
		setUnit,
		setCustomValue,
		syncFromPC,
		enabledBreakpoints,
	};
};

export const getResponsiveAttrValue = (
	attributes,
	baseName,
	device,
	options = {}
) => {
	const {
		hoverSuffix = '',
		valueKey = '',
		unitKey = 'Unit',
		defaultUnit = 'px',
	} = options;

	const getAttrName = ( bp, suffix = '' ) =>
		`${ baseName }${ bp.toUpperCase() }${ hoverSuffix }${ suffix }`;

	const directValue = attributes[ getAttrName( device, valueKey ) ];
	const unit = attributes[ getAttrName( device, unitKey ) ] || defaultUnit;

	if (
		directValue !== undefined &&
		directValue !== '' &&
		directValue !== null
	) {
		return { value: directValue, unit };
	}

	const enabledBreakpoints = getEnabledBreakpoints();
	const currentIndex = enabledBreakpoints.indexOf( device );
	for ( let i = currentIndex - 1; i >= 0; i-- ) {
		const bp = enabledBreakpoints[ i ];
		const inheritedValue = attributes[ getAttrName( bp, valueKey ) ];
		const inheritedUnit =
			attributes[ getAttrName( bp, unitKey ) ] || defaultUnit;
		if (
			inheritedValue !== undefined &&
			inheritedValue !== '' &&
			inheritedValue !== null
		) {
			return { value: inheritedValue, unit: inheritedUnit };
		}
	}

	return { value: '', unit: defaultUnit };
};
