import { React, classnames, PropTypes } from '@gravityforms/libraries';
import Icon from '../../elements/Icon';
import Text from '../../elements/Text';

const { forwardRef } = React;

/**
 * @module DroplistItem
 * @description The DroplistItem component.
 *
 * @since 4.3.0
 *
 * @param {object}              props                      Props for the DroplistItem component.
 * @param {object}              props.customAttributes     Custom attributes for the droplist item.
 * @param {string|Array|object} props.customClasses        Custom classes for the droplist item.
 * @param {number}              props.depth                The depth of the droplist item.
 * @param {string}              props.element              The element type to render, one of `button` or `link`.
 * @param {string}              props.iconAfter            The icon after the text.
 * @param {object}              props.iconAfterAttributes  Custom attributes for the icon after the text.
 * @param {string|Array|object} props.iconAfterClasses     Custom classes for the icon after the text.
 * @param {string}              props.iconBefore           The icon before the text.
 * @param {object}              props.iconBeforeAttributes Custom attributes for the icon before the text.
 * @param {string|Array|object} props.iconBeforeClasses    Custom classes for the icon before the text.
 * @param {string}              props.iconPrefix           The icon prefix to use.
 * @param {number}              props.index                The index of the droplist item.
 * @param {string}              props.label                The label to display.
 * @param {object}              props.labelAttributes      Custom attributes for the label component.
 * @param {string|Array|object} props.labelClasses         Custom classes for the label component.
 * @param {object}              props.propsWithState       Props and state to pass to the droplist item.
 * @param {string}              props.style                The style of the droplist item, one of `info` or `error`.
 * @param {object|null}         ref                        Ref to the component.
 *
 * @return {JSX.Element|null} The DroplistItem component.
 */
export const DroplistItem = forwardRef( ( {
	customAttributes = {},
	customClasses = [],
	depth = 0,
	element = 'button',
	iconAfter = '',
	iconAfterAttributes = {},
	iconAfterClasses = [],
	iconBefore = '',
	iconBeforeAttributes = {},
	iconBeforeClasses = [],
	iconPrefix = 'gravity-component-icon',
	index = 0,
	label = '',
	labelAttributes = {},
	labelClasses = [],
	propsWithState = {},
	style = 'info',
}, ref ) => {
	// Check if element type is valid, return null if not.
	if ( ! [ 'button', 'link' ].includes( element ) ) {
		return null;
	}

	const { openOnHover, selectedState, setSelectedState, stackNestedGroups } = propsWithState;

	const setSelectedStateOpen = () => {
		const { id = '' } = customAttributes;
		// If the group is already open, do nothing.
		if ( selectedState[ depth ] === id ) {
			return;
		}
		const depthKeys = Object.keys( selectedState );
		const filteredState = depthKeys
			.filter( ( key ) => key < depth )
			.reduce( ( acc, key ) => {
				acc[ key ] = selectedState[ key ];
				return acc;
			}, {} );
		const newSelectedState = {
			...filteredState,
			[ depth ]: id,
		};
		setSelectedState( newSelectedState );
	};

	const triggerProps = {
		className: classnames( {
			'gform-droplist__item-trigger': true,
			[ `gform-droplist__item-trigger--${ style }` ]: true,
			[ `gform-droplist__item-trigger--depth-${ depth }` ]: true,
			[ `gform-droplist__item-trigger--${ index }` ]: true,
			'gform-droplist__item-trigger--disabled': element === 'button' && customAttributes.disabled,
		}, customClasses ),
		onMouseEnter: openOnHover && ! stackNestedGroups ? () => {
			setSelectedStateOpen();
		} : undefined,
		...customAttributes,
	};
	if ( propsWithState.closeOnClick ) {
		triggerProps.onClick = ( event ) => {
			const { onClick = () => {} } = customAttributes;
			onClick( event );
			propsWithState.closeDroplist();
		};
	}

	const iconBeforeProps = {
		icon: iconBefore,
		iconPrefix,
		customClasses: classnames( {
			'gform-droplist__item-trigger-icon': true,
			'gform-droplist__item-trigger-icon--before': true,
		}, iconBeforeClasses ),
		...iconBeforeAttributes,
	};
	const iconAfterProps = {
		icon: iconAfter,
		iconPrefix,
		customClasses: classnames( {
			'gform-droplist__item-trigger-icon': true,
			'gform-droplist__item-trigger-icon--after': true,
		}, iconAfterClasses ),
		...iconAfterAttributes,
	};
	const labelProps = {
		content: label,
		customClasses: classnames( {
			'gform-droplist__item-trigger-text': true,
		}, labelClasses ),
		color: style === 'error' ? 'red' : undefined,
		size: 'text-sm',
		...labelAttributes,
	};
	const Component = element === 'link' ? 'a' : element;

	return (
		<Component ref={ ref } { ...triggerProps }>
			{ iconBefore && <Icon { ...iconBeforeProps } /> }
			{ label && <Text { ...labelProps } /> }
			{ iconAfter && <Icon { ...iconAfterProps } /> }
		</Component>
	);
} );

DroplistItem.propTypes = {
	customAttributes: PropTypes.object,
	customClasses: PropTypes.oneOfType( [
		PropTypes.string,
		PropTypes.array,
		PropTypes.object,
	] ),
	depth: PropTypes.number,
	element: PropTypes.oneOf( [ 'button', 'link' ] ),
	iconAfter: PropTypes.string,
	iconAfterAttributes: PropTypes.object,
	iconAfterClasses: PropTypes.oneOfType( [
		PropTypes.string,
		PropTypes.array,
		PropTypes.object,
	] ),
	iconBefore: PropTypes.string,
	iconBeforeAttributes: PropTypes.object,
	iconBeforeClasses: PropTypes.oneOfType( [
		PropTypes.string,
		PropTypes.array,
		PropTypes.object,
	] ),
	iconPrefix: PropTypes.string,
	label: PropTypes.string,
	labelAttributes: PropTypes.object,
	labelClasses: PropTypes.oneOfType( [
		PropTypes.string,
		PropTypes.array,
		PropTypes.object,
	] ),
	propsWithState: PropTypes.object,
	style: PropTypes.oneOf( [ 'info', 'error' ] ),
};

DroplistItem.displayName = 'DroplistItem';

export default DroplistItem;
