/**
 * UnitControl that also accepts CSS keywords / freeform values (auto, calc(), …).
 */
import {
	BaseControl,
	Button,
	TextControl,
	__experimentalUnitControl as UnitControl,
} from '@wordpress/components';
import { useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { SPACING_UNITS } from '../styleFieldDefaults';
const CSS_KEYWORDS = new Set( [
	'auto',
	'inherit',
	'initial',
	'unset',
	'revert',
	'revert-layer',
	'none',
	'normal',
	'max-content',
	'min-content',
	'fit-content',
	'stretch',
	'content',
] );

/**
 * @param {string} value
 * @return {boolean}
 */
export function isCssKeywordValue( value ) {
	const v = String( value || '' ).trim().toLowerCase();
	if ( ! v ) {
		return false;
	}
	if ( CSS_KEYWORDS.has( v ) ) {
		return true;
	}
	if ( v.startsWith( 'fit-content(' ) ) {
		return true;
	}
	return /^(calc|clamp|min|max|var)\(/i.test( v );
}

/**
 * @param {string} value
 * @param {Array<{ value: string }>} units
 * @return {boolean}
 */
export function isUnitLikeValue( value, units = SPACING_UNITS ) {
	const v = String( value || '' ).trim();
	if ( ! v || isCssKeywordValue( v ) ) {
		return false;
	}
	if ( /^-?[\d.]+$/.test( v ) ) {
		return true;
	}
	const unitPart = ( units || [] )
		.map( ( u ) => String( u.value ).replace( /[.*+?^${}()|[\]\\]/g, '\\$&' ) )
		.join( '|' );
	if ( ! unitPart ) {
		return /^-?[\d.]+[a-z%]+$/i.test( v );
	}
	return new RegExp( `^-?[\\d.]+(?:${ unitPart })$`, 'i' ).test( v );
}

/**
 * @param {object}   props
 * @param {string}   [props.label]
 * @param {string}   [props.help]
 * @param {string}   [props.value]
 * @param {Function} props.onChange
 * @param {Array}    [props.units]
 * @param {string}   [props.className]
 * @param {boolean}  [props.hideLabelFromVision]
 * @param {string}   [props.placeholder]
 */
export default function FlexibleUnitControl( {
	label,
	help,
	value = '',
	onChange,
	units = SPACING_UNITS,
	className = '',
	hideLabelFromVision = false,
	placeholder,
} ) {
	const unitLike = isUnitLikeValue( value, units );
	const [ forceText, setForceText ] = useState( false );
	const useText = forceText || ( Boolean( value ) && ! unitLike );
	const wrapLabel = Boolean( label ) && ! hideLabelFromVision;

	const field = useText ? (
		<TextControl
			label={ label || __( 'Custom', 'joc-blockora-morph' ) }
			hideLabelFromVision={ wrapLabel || hideLabelFromVision }
			value={ value || '' }
			onChange={ ( next ) => {
				const nextVal = next || '';
				if ( isUnitLikeValue( nextVal, units ) ) {
					setForceText( false );
				}
				onChange( nextVal );
			} }
			placeholder={
				placeholder ||
				__( 'e.g. auto, 16px, 50%, calc(100% - 2rem)', 'joc-blockora-morph' )
			}
			__nextHasNoMarginBottom
			__next40pxDefaultSize
		/>
	) : (
		<UnitControl
			label={ label || __( 'Custom', 'joc-blockora-morph' ) }
			hideLabelFromVision={ wrapLabel || hideLabelFromVision }
			value={ value || '' }
			onChange={ ( next ) => onChange( next || '' ) }
			units={ units }
			__next40pxDefaultSize
			__nextHasNoMarginBottom
		/>
	);

	const toggle = (
		<div className="bm-flexible-unit__toggle">
			<Button
				variant="link"
				className="bm-flexible-unit__toggle-btn"
				onClick={ () => {
					if ( useText ) {
						setForceText( false );
						if ( value && ! isUnitLikeValue( value, units ) ) {
							onChange( '' );
						}
						return;
					}
					setForceText( true );
					if ( ! value || isUnitLikeValue( value, units ) ) {
						onChange( 'auto' );
					}
				} }
			>
				{ useText
					? __( 'Use unit control', 'joc-blockora-morph' )
					: __( 'Use auto / CSS value', 'joc-blockora-morph' ) }
			</Button>
		</div>
	);

	const wrapped = (
		<div
			className={ [ 'bm-flexible-unit', className ].filter( Boolean ).join( ' ' ) }
		>
			{ field }
			{ toggle }
		</div>
	);

	if ( ! wrapLabel ) {
		return wrapped;
	}

	return (
		<BaseControl label={ label } help={ help } className="bm-flexible-unit-wrap">
			{ wrapped }
		</BaseControl>
	);
}
