import { React, PropTypes, classnames } from '@gravityforms/libraries';
import { useIdContext, useStoreContext } from '@gravityforms/react-utils';
import {
	NEEDS_I18N_LABEL,
	getId,
	getComponent,
} from './utils';

const { forwardRef } = React;

/**
 * @module DropdownTrigger
 * @description The trigger for the dropdown.
 *
 * @since 4.5.0
 *
 * @param {object}              props                      Component props.
 * @param {boolean}             props.disabled             Whether the dropdown is disabled.
 * @param {Function}            props.handleBlur           The blur event handler.
 * @param {Function}            props.handleEscKeyDown     The escape keydown event handler.
 * @param {Function}            props.handleKeyDownCapture The keydown capture event handler.
 * @param {Function}            props.handleTriggerKeyDown The trigger keydown event handler.
 * @param {object}              props.i18n                 The i18n object.
 * @param {string}              props.label                The label for the dropdown.
 * @param {boolean}             props.multi                Whether the dropdown is multi-select.
 * @param {Function}            props.open                 The open function.
 * @param {Function}            props.resetAndClose        The reset and close function.
 * @param {object}              props.triggerAttributes    Custom attributes for the trigger.
 * @param {string|Array|object} props.triggerClasses       Custom classes for the trigger.
 * @param {object}              ref                        Ref to the component.
 *
 * @return {JSX.Element} The trigger component.
 */
const DropdownTrigger = forwardRef( ( {
	disabled = false,
	handleBlur = () => {},
	handleEscKeyDown = () => {},
	handleKeyDownCapture = () => {},
	handleTriggerKeyDown = () => {},
	i18n = {},
	label = '',
	multi = false,
	open = () => {},
	resetAndClose = () => {},
	triggerAttributes = {},
	triggerClasses = [],
}, ref ) => {
	const id = useIdContext();
	const dropdownOpen = useStoreContext( ( state ) => state.open );
	const selectedItem = useStoreContext( ( state ) => state.selectedItem );
	const triggerHeight = useStoreContext( ( state ) => state.triggerHeight );

	const popoverId = getId( id, 'popover' );
	const labelId = getId( id, 'label' );
	const pillsId = getId( id, 'pills' );

	const triggerProps = {
		className: classnames( [
			'gform-dropdown__trigger',
			'gform-text',
			'gform-text--color-port',
			'gform-typography--size-text-sm',
			'gform-typography--weight-regular',
		], triggerClasses ),
		...triggerAttributes,
		'aria-autocomplete': 'none',
		'aria-controls': popoverId,
		'aria-expanded': dropdownOpen ? 'true' : 'false',
		'aria-haspopup': 'listbox',
		disabled,
		onBlur: handleBlur,
		onClick: ( event ) => {
			const clickHandler = dropdownOpen ? resetAndClose : open;
			clickHandler( event );
		},
		onKeyDown: ( event ) => {
			handleEscKeyDown( event );
			handleTriggerKeyDown( event );
		},
		onKeyDownCapture: ( event ) => handleKeyDownCapture( event ),
		role: 'combobox',
		type: 'button',
	};
	if ( label ) {
		triggerProps[ 'aria-labelledby' ] = labelId;
	}
	if ( multi ) {
		triggerProps[ 'aria-describedby' ] = pillsId;
	}
	if ( triggerHeight ) {
		triggerProps.style = {
			height: `${ triggerHeight }px`,
		};
	}

	/**
	 * @function getSingleTriggerLabel
	 * @description Get the label for the single dropdown trigger.
	 *
	 * @since 4.5.0
	 *
	 * @return {JSX.Element} The label for the single dropdown trigger.
	 */
	const getSingleTriggerLabel = () => (
		<>
			{ selectedItem.beforeLabel && (
				<span className="gform-dropdown__trigger-before-label">
					{ getComponent( selectedItem.beforeLabel ) }
				</span>
			) }
			<span className="gform-dropdown__trigger-label">{ selectedItem.label }</span>
			{ selectedItem.afterLabel && (
				<span className="gform-dropdown__trigger-after-label">
					{ getComponent( selectedItem.afterLabel ) }
				</span>
			) }
		</>
	);

	/**
	 * @function getMultiTriggerLabel
	 * @description Get the label for the multi dropdown trigger.
	 *
	 * @since 4.5.0
	 *
	 * @return {string|JSX.Element} The label for the multi dropdown trigger.
	 */
	const getMultiTriggerLabel = () => {
		if ( selectedItem.length ) {
			return (
				<span className="gform-visually-hidden">
					{ selectedItem.map( ( item ) => item.label ).join( ', ' ) }
				</span>
			);
		}

		return i18n.multiTriggerLabel || NEEDS_I18N_LABEL;
	};

	return (
		<button { ...triggerProps } ref={ ref }>
			{ multi ? getMultiTriggerLabel() : getSingleTriggerLabel() }
		</button>
	);
} );

DropdownTrigger.propTypes = {
	disabled: PropTypes.bool,
	handleBlur: PropTypes.func,
	handleEscKeyDown: PropTypes.func,
	handleKeyDownCapture: PropTypes.func,
	handleTriggerKeyDown: PropTypes.func,
	i18n: PropTypes.object,
	label: PropTypes.string,
	multi: PropTypes.bool,
	open: PropTypes.func,
	resetAndClose: PropTypes.func,
	triggerAttributes: PropTypes.object,
	triggerClasses: PropTypes.oneOfType( [
		PropTypes.string,
		PropTypes.array,
		PropTypes.object,
	] ),
};

export default DropdownTrigger;
