import { useEffect, useRef, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import clsx from '../../../utils/clsx';
import { IconButton, SelectBox } from '../../molecules';
import { Button } from '../Button';
import { Text } from '../Text';

const Slider = ( {
	id,
	style,
	className = '',
	size = 'small',
	min = 0,
	max = 100,
	step = 1,
	value = 50,
	defaultValue = 50,
	reset = false,
	showMark = false,
	marks = [],
	unit = false,
	unitOptions = [],
	unitValue = [],
	defaultUnit = '',
	unitPlaceholder = __( 'Unit', 'rewind-form-bridge-for-brevo' ),
	trackDisabled = false,
	disabled = false,
	onlyInput = false,
	onChange,
} ) => {
	const [ inputValue, setInputValue ] = useState( value );
	const [ isDragging, setIsDragging ] = useState( false );
	const [ tooltipLeft, setTooltipLeft ] = useState( 0 );
	const [ error, setError ] = useState( '' );

	const trackRef = useRef( null );

	useEffect( () => {
		setInputValue( value );
	}, [ value ] );

	const percent = ( ( value - min ) / ( max - min ) ) * 100;

	const updateValueFromClientX = ( clientX ) => {
		if ( ! trackRef.current ) return;
		const rect = trackRef.current.getBoundingClientRect();
		let newPercent = ( ( clientX - rect.left ) / rect.width ) * 100;
		newPercent = Math.max( 0, Math.min( 100, newPercent ) );
		const newValue =
			Math.round(
				( min + ( newPercent / 100 ) * ( max - min ) ) / step
			) * step;
		handleOnchange( newValue, unitValue[ 0 ] );
		setError( '' );
	};

	const handleMouseDown = ( e ) => {
		if ( disabled || trackDisabled ) return;
		setIsDragging( true );
		updateValueFromClientX( e.clientX );
	};

	const handleMouseMove = ( e ) => {
		if ( ! isDragging || disabled || trackDisabled ) return;
		updateValueFromClientX( e.clientX );
	};

	const handleMouseUp = () => {
		if ( isDragging ) setIsDragging( false );
	};

	useEffect( () => {
		if ( isDragging ) {
			window.addEventListener( 'mousemove', handleMouseMove );
			window.addEventListener( 'mouseup', handleMouseUp );
		} else {
			window.removeEventListener( 'mousemove', handleMouseMove );
			window.removeEventListener( 'mouseup', handleMouseUp );
		}
		return () => {
			window.removeEventListener( 'mousemove', handleMouseMove );
			window.removeEventListener( 'mouseup', handleMouseUp );
		};
	}, [ isDragging ] );

	useEffect( () => {
		if ( trackRef.current ) {
			const trackWidth = trackRef.current.offsetWidth;
			const thumbWidth = 14;
			const left =
				( percent / 100 ) * ( trackWidth - thumbWidth ) +
				thumbWidth / 2;
			setTooltipLeft( left );
		}
	}, [ value, percent ] );

	const getMarkPosition = ( markValue ) => {
		if ( ! trackRef.current ) return 0;
		const trackWidth = trackRef.current.offsetWidth;
		const thumbWidth = 14;
		const markPercent = ( markValue - min ) / ( max - min );
		return markPercent * ( trackWidth - thumbWidth ) + thumbWidth / 2;
	};

	const handleOnchange = ( newValue, newUnit ) => {
		if ( disabled ) return;

		setError( '' );

		const isNewUnit = newUnit && unitValue[ 0 ] !== newUnit;

		const defaultUnitValue = unitOptions.find(
			( option ) => option.value === newUnit
		)?.defaultValue;

		onChange( isNewUnit ? defaultUnitValue : newValue, newUnit );
	};

	const handleReset = () => {
		if ( disabled ) return;
		handleOnchange( defaultValue, defaultUnit );
		setError( '' );
	};

	return (
		<div
			id={ id }
			style={ style }
			className={ clsx(
				'rbfb-slider',
				size === 'small' && 'rbfb-slider--small',
				disabled && 'rbfb-slider--disabled',
				onlyInput && 'rbfb-slider--only-input',
				className
			) }
		>
			{ ! onlyInput && (
				<div
					className={ clsx(
						'rbfb-slider__track-container',
						trackDisabled &&
							'rbfb-slider__track-container--disabled'
					) }
				>
					<div
						ref={ trackRef }
						className="rbfb-slider__track-container-wrapper"
						onMouseDown={ handleMouseDown }
					>
						<div className="rbfb-slider__track-container-wrapper-track">
							<div
								className="rbfb-slider__track-container-wrapper-track-fill"
								style={ { width: `${ percent }%` } }
							/>

							<div
								style={ { left: `${ percent }%` } }
								className={ clsx(
									'rbfb-slider__track-container-wrapper-thumb',
									isDragging &&
										'rbfb-slider__track-container-wrapper-thumb--active'
								) }
							/>
						</div>

						<div
							className="rbfb-slider__track-container-wrapper-tooltip"
							style={ { left: `${ tooltipLeft }px` } }
						>
							{ value }
						</div>
					</div>

					{ showMark && (
						<div className="rbfb-slider-marks">
							{ marks.map(
								( { name, value: markValue }, index ) => {
									const markLeft =
										getMarkPosition( markValue );
									const isActive = value === markValue;
									const isPassed = value >= markValue;

									return (
										<div
											key={ index }
											style={ {
												position: 'absolute',
												left: `${ markLeft }px`,
												transform: 'translateX(-50%)',
											} }
											className={ clsx(
												'rbfb-slider-mark',
												isActive &&
													'rbfb-slider-mark--active',
												isPassed &&
													'rbfb-slider-mark--passed'
											) }
											onClick={ () => {
												setError( '' );
												! disabled &&
													handleOnchange(
														markValue,
														unitValue[ 0 ]
													);
											} }
										>
											{ name }
										</div>
									);
								}
							) }
						</div>
					) }
				</div>
			) }

			<div
				className={ clsx(
					'rbfb-slider-input-container',
					unit ? '' : 'rbfb-slider-input-container--no-unit',
					onlyInput && 'rbfb-slider-input-container--only-input'
				) }
			>
				<input
					type="number"
					value={ inputValue }
					step={ step }
					disabled={ disabled }
					className={ clsx(
						'rbfb-slider-input-box',
						onlyInput && 'rbfb-slider-input-box--only-input'
					) }
					onChange={ ( e ) => {
						setInputValue( e.target.value );
						setError( '' );
						if ( max < Number( e.target.value ) ) {
							setError(
								`${ __(
									'Value exceeds maximum',
									'rewind-form-bridge-for-brevo'
								) } ${ max } ${
									unitValue[ 0 ] ? unitValue[ 0 ] : ''
								}`
							);
							return;
						}
						if ( min > Number( e.target.value ) ) {
							setError(
								`${ __(
									'Value is below minimum',
									'rewind-form-bridge-for-brevo'
								) } ${ min } ${
									unitValue[ 0 ] ? unitValue[ 0 ] : ''
								}`
							);
							return;
						}
						handleOnchange(
							Number( e.target.value ),
							unitValue[ 0 ]
						);
					} }
				/>

				{ unit && <div className="rbfb-slider-input-divider" /> }

				{ unit && (
					<SelectBox
						size={ size === 'small' ? 'small' : 'medium' }
						borderStyle="none"
						background={ onlyInput ? 'gray-50' : 'white' }
						options={ unitOptions }
						value={ unitValue }
						placeholder={ unitPlaceholder }
						onChange={ ( newUnitValue ) =>
							handleOnchange( value, newUnitValue[ 0 ] )
						}
						disabled={ disabled }
					/>
				) }
			</div>

			{ reset && ! onlyInput && (
				<Button
					variant="error"
					size={ size === 'small' ? 'small' : 'medium' }
					onClick={ handleReset }
					disabled={ disabled }
				>
					{ __( 'Reset', 'rewind-form-bridge-for-brevo' ) }
				</Button>
			) }

			{ reset && onlyInput && (
				<IconButton
					variant="gray"
					color="gray-600"
					name="mop"
					size={ size === 'small' ? 'small' : 'medium' }
					onClick={ handleReset }
					disabled={ disabled }
				/>
			) }

			{ error && (
				<Text color="error" size="sm">
					{ error }
				</Text>
			) }
		</div>
	);
};

export default Slider;
