import { React, PropTypes, classnames } from '@gravityforms/libraries';
import { sprintf } from '@gravityforms/utils';
import CommonSimpleFilters from '../../../utils/CommonSimpleFilters';
import { SEARCH_KEY } from '../utils';

const { forwardRef } = React;

/**
 * @function augmentListItem
 * @description Augment a list item with an onClick handler.
 *
 * @since 5.8.4
 *
 * @param {object}   item                     The list item.
 * @param {object}   props                    The component props.
 * @param {boolean}  props.isLoading          Whether the kanban is loading.
 * @param {object}   props.listItemAttributes The list item attributes.
 * @param {Function} props.onFilterChange     The filter change handler.
 * @param {object}   props.moduleState        The module state.
 * @param {Function} props.setIsLoading       The set loading state handler.
 * @param {Function} props.updateModuleState  The update module state handler.
 * @param {boolean}  props.useAjax            Whether to use ajax or not.
 *
 * @return {object} The augmented list item.
 */
const augmentListItem = (
	item = {},
	{
		isLoading = false,
		listItemAttributes = {},
		onFilterChange = () => {},
		moduleState = {},
		setIsLoading = () => {},
		updateModuleState = () => {},
		useAjax = false,
	},
) => {
	if ( item?.props?.element === 'link' ) {
		return item;
	}

	const {
		iconAfter = '',
		iconPrefix = '',
	} = listItemAttributes;

	const { onClick: filterOnClick = () => {} } = item?.props?.customAttributes || {};
	const { filters = [] } = moduleState;
	const hasFilter = filters.find( ( filter ) => filter.id === item.props.customAttributes?.id );

	const onClick = ( event ) => {
		if ( ! useAjax ) {
			return;
		}

		if ( isLoading ) {
			return;
		}

		filterOnClick( event );
		const updatedFilters = hasFilter
			? filters.filter( ( filter ) => filter.id !== item.props.customAttributes?.id )
			: [
				...filters,
				{
					key: item.props.customAttributes?.[ 'data-key' ] || '',
					value: item.props.customAttributes?.[ 'data-value' ] || '',
					id: item.props.customAttributes?.id || '',
					label: item.props.customAttributes?.[ 'data-pill-label' ] || '',
				},
			];
		const updatedState = {
			filters: updatedFilters,
		};
		const combinedState = { ...moduleState, ...updatedState };
		setIsLoading( true );
		onFilterChange( combinedState )
			.then( () => {
				updateModuleState( updatedState );
				setIsLoading( false );
			} )
			.catch( ( error ) => {
				setIsLoading( false );
				console.info( error );
			} );
	};

	return {
		...item,
		props: {
			...( item?.props || {} ),
			customAttributes: {
				...( item?.props?.customAttributes || {} ),
				onClick,
			},
			iconAfter: hasFilter ? iconAfter : undefined,
			iconPrefix,
		},
	};
};

/**
 * @function augmentListItems
 * @description Augment a list of items with onClick handlers.
 *
 * @since 5.8.4
 *
 * @param {Array}  items The list of items.
 * @param {object} props The component props.
 * @param {number} depth The depth of the list.
 *
 * @return {Array} The augmented list items.
 */
const augmentListItems = ( items = [], props = {}, depth = 0 ) => {
	const {
		isLoading = false,
		moduleState = {},
		setIsLoading = () => {},
		updateModuleState = () => {},
		listItemAttributes: {
			groupIcon = '',
			iconPrefix = '',
		} = {},
		onFilterChange = () => {},
		reset: {
			hasReset = false,
			label = '',
		},
		useAjax = false,
	} = props;

	const augmentedItems = items.map( ( item, index ) => {
		if ( item.listItems ) {
			// has list items, call recursive.
			const triggerAttributes = { ...( item?.triggerAttributes || {} ) };
			if ( groupIcon ) {
				triggerAttributes.iconAfter = groupIcon;
			}
			if ( iconPrefix ) {
				triggerAttributes.iconPrefix = iconPrefix;
			}
			return {
				...item,
				triggerAttributes,
				customClasses: classnames(
					'gform-kanban__controls-simple-filters-list-item',
					'gform-kanban__controls-simple-filters-list-item--group',
					item.customClasses || [],
				),
				listItems: augmentListItems( item.listItems, props, depth + 1 ),
				hasDivider: index === items.length - 1 && hasReset && depth === 0,
			};
		}

		return augmentListItem( item, props );
	} );

	if ( hasReset && depth === 0 ) {
		augmentedItems.push( {
			key: 'reset',
			customClasses: [ 'gform-kanban__controls-simple-filters-list-item', 'gform-kanban__controls-simple-filters-list-item--reset' ],
			props: {
				element: 'button',
				label,
				customAttributes: {
					id: 'reset',
					onClick: () => {
						if ( ! useAjax ) {
							return;
						}

						if ( isLoading ) {
							return;
						}

						const { filters = [] } = moduleState;
						const updatedFilters = filters.filter( ( filter ) => SEARCH_KEY === filter.key );
						const updatedState = {
							filters: updatedFilters,
						};
						const combinedState = { ...moduleState, ...updatedState };
						setIsLoading( true );
						onFilterChange( combinedState )
							.then( () => {
								updateModuleState( updatedState );
								setIsLoading( false );
							} )
							.catch( ( error ) => {
								setIsLoading( false );
								console.info( error );
							} );
					},
				},
			},
		} );
	}

	return augmentedItems;
};

/**
 * @module SimpleFilters
 * @description The Simple Filters module for the kanban.
 *
 * @since 5.8.4
 *
 * @param {object}      props                   The component props.
 * @param {boolean}     props.isLoading         Whether the kanban is loading.
 * @param {object}      props.moduleAttributes  The attributes for the module.
 * @param {object}      props.moduleState       The state of the module.
 * @param {Function}    props.setIsLoading      The function to set the loading state.
 * @param {Function}    props.updateModuleState The function to update the module state.
 * @param {boolean}     props.useAjax           Whether to use ajax or not.
 * @param {object|null} ref                     Ref to the component.
 *
 * @return {JSX.Element} The Simple Filters component.
 */
const SimpleFilters = forwardRef( ( props, ref ) => {
	const defaultProps = {
		isLoading: false,
		moduleAttributes: {},
		moduleState: {},
		setIsLoading: () => {},
		updateModuleState: () => {},
		useAjax: false,
	};
	const combinedProps = { ...defaultProps, ...props };
	const {
		isLoading,
		moduleAttributes,
		moduleState,
	} = combinedProps;

	const {
		droplist: {
			customClasses = [],
			listItems = [],
			listItemAttributes = {},
			reset = {},
			triggerAttributes: {
				ariaText = '',
				...restTriggerAttributes
			} = {},
			...restDroplistAttributes
		} = {},
		onFilterChange = () => {},
	} = moduleAttributes?.simpleFilters || {};
	const { filters = [] } = moduleState;
	const augmentedListItems = augmentListItems(
		listItems,
		{
			listItemAttributes,
			onFilterChange,
			reset,
			...combinedProps,
		},
		0,
	);
	const numFilters = filters.filter( ( filter ) => SEARCH_KEY !== filter.key ).length;
	const updatedAriaText = sprintf( ariaText, numFilters );

	const componentProps = {
		count: numFilters,
		countClasses: [ 'gform-kanban__controls-simple-filters-count' ],
		customClasses: [ 'gform-kanban__controls-simple-filters' ],
		droplistAttributes: {
			listItems: augmentedListItems,
			triggerAttributes: {
				ariaText: updatedAriaText,
				...restTriggerAttributes,
				disabled: isLoading,
			},
			...restDroplistAttributes,
		},
		droplistClasses: classnames(
			'gform-kanban__controls-simple-filters-droplist',
			customClasses,
		),
	};

	return <CommonSimpleFilters { ...componentProps } ref={ ref } />;
} );

SimpleFilters.propTypes = {
	isLoading: PropTypes.bool,
	moduleAttributes: PropTypes.object,
	moduleState: PropTypes.object,
	setIsLoading: PropTypes.func,
	updateModuleState: PropTypes.func,
	useAjax: PropTypes.bool,
};

SimpleFilters.displayName = 'SimpleFilters';

/**
 * @function getDefaultState
 * @description Returns the default state.
 *
 * @since 5.8.4
 *
 * @return {object} The default state.
 */
const getDefaultState = () => ( {
	filters: [],
} );

export default {
	name: 'SimpleFilters',
	SimpleFilters,
	getDefaultState,
};
