/**
 * Category filter chip — hierarchical multi-select for product categories.
 *
 * @package RawTypeOE
 */

import { useCallback, useEffect, useMemo, useState } from '@wordpress/element';
import { __, _n, sprintf } from '@wordpress/i18n';
import { Badge, Checkbox, EmptyState, Label, Notice, Skeleton } from '@rawtype/ui';
import useApiData from '../hooks/useApiData';

/**
 * Count total products in a category node including all descendants.
 *
 * @param {Object} cat Category node with count and children.
 * @return {number} Total product count.
 */
function getTotalCount( cat ) {
	let total = cat.count || 0;
	if ( cat.children && cat.children.length > 0 ) {
		for ( const child of cat.children ) {
			total += getTotalCount( child );
		}
	}
	return total;
}

/**
 * Recursively render a category tree with checkboxes, counts, and collapsible parents.
 *
 * @param {Object}   props              Component props.
 * @param {Array}    props.categories   Category tree nodes.
 * @param {Array}    props.selected     Selected category IDs.
 * @param {Function} props.onToggle     Toggle handler.
 * @param {Object}   props.collapsed    Collapsed state map { [catId]: boolean }.
 * @param {Function} props.onToggleCollapse Toggle collapse handler.
 * @param {number}   props.depth        Current depth level.
 * @return {JSX.Element} Rendered tree.
 */
function CategoryTree( { categories, selected, onToggle, collapsed, onToggleCollapse, depth = 0 } ) {
	return (
		<div className="roe-category-tree" style={ { paddingLeft: depth * 16 } }>
			{ categories.map( ( cat ) => {
				const isChecked = selected.includes( cat.id );
				const hasChildren = cat.children && cat.children.length > 0;
				const isCollapsed = hasChildren && collapsed[ cat.id ];
				const totalCount = getTotalCount( cat );

				return (
					<div key={ cat.id } className="roe-category-node">
						{ /* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */ }
						<div
							className={ 'roe-category-option' + ( isChecked ? ' roe-category-option--checked' : '' ) }
							onClick={ () => onToggle( cat.id ) }
						>
							{ hasChildren && (
								<button
									type="button"
									className={ 'roe-category-toggle' + ( isCollapsed ? '' : ' roe-category-toggle--open' ) }
									onClick={ ( e ) => {
										e.stopPropagation();
										onToggleCollapse( cat.id );
									} }
									aria-expanded={ ! isCollapsed }
									aria-label={ isCollapsed
										? sprintf(
											/* translators: %s: category name */
											__( 'Expand %s', 'rawtype-order-exporter-woocommerce' ),
											cat.name,
										)
										: sprintf(
											/* translators: %s: category name */
											__( 'Collapse %s', 'rawtype-order-exporter-woocommerce' ),
											cat.name,
										)
									}
								>
									<span className="dashicons dashicons-arrow-right-alt2" aria-hidden="true" />
								</button>
							) }
							{ /* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */ }
							<span onClick={ ( e ) => e.stopPropagation() }>
								<Checkbox
									id={ 'roe-cat-' + cat.id }
									checked={ isChecked }
									onCheckedChange={ () => onToggle( cat.id ) }
									label={ cat.name }
								/>
							</span>
							<Badge variant="inset" className="roe-category-count">
								{ totalCount }
							</Badge>
						</div>
						{ hasChildren && ! isCollapsed && (
							<CategoryTree
								categories={ cat.children }
								selected={ selected }
								onToggle={ onToggle }
								collapsed={ collapsed }
								onToggleCollapse={ onToggleCollapse }
								depth={ depth + 1 }
							/>
						) }
					</div>
				);
			} ) }
		</div>
	);
}

export default function CategoryFilterChip( { filter, onChange } ) {
	const { data: categories, loading, error } = useApiData( '/rawtype_oe/v1/categories' );

	const initialCollapsed = useMemo( () => {
		const result = {};
		const collapseParents = ( nodes ) => {
			for ( const node of nodes ) {
				if ( node.children && node.children.length > 0 ) {
					result[ node.id ] = true;
					collapseParents( node.children );
				}
			}
		};
		collapseParents( categories );
		return result;
	}, [ categories ] );

	const [ collapsed, setCollapsed ] = useState( {} );
	// Sync collapsed state when categories load.
	useEffect( () => {
		if ( categories.length > 0 ) {
			setCollapsed( initialCollapsed );
		}
	}, [ initialCollapsed, categories.length ] );

	const selectedValues = Array.isArray( filter.value ) ? filter.value : [];

	const handleToggle = useCallback(
		( categoryId ) => {
			const next = selectedValues.includes( categoryId )
				? selectedValues.filter( ( v ) => v !== categoryId )
				: [ ...selectedValues, categoryId ];

			onChange( { ...filter, value: next } );
		},
		[ filter, onChange, selectedValues ],
	);

	const handleToggleCollapse = useCallback(
		( categoryId ) => {
			setCollapsed( ( prev ) => ( {
				...prev,
				[ categoryId ]: ! prev[ categoryId ],
			} ) );
		},
		[],
	);

	if ( loading ) {
		return <Skeleton width="100%" height={ 80 } />;
	}

	if ( error ) {
		return (
			<Notice type="error">
				{ __( 'Error loading categories', 'rawtype-order-exporter-woocommerce' ) }
			</Notice>
		);
	}

	if ( 0 === categories.length ) {
		return (
			<EmptyState
				title={ __( 'No categories', 'rawtype-order-exporter-woocommerce' ) }
				description={ __( 'No product categories found', 'rawtype-order-exporter-woocommerce' ) }
			/>
		);
	}

	return (
		<div className="roe-category-filter">
			<Label size="sm">
				{ __( 'Product category', 'rawtype-order-exporter-woocommerce' ) }
			</Label>
			<CategoryTree
				categories={ categories }
				selected={ selectedValues }
				onToggle={ handleToggle }
				collapsed={ collapsed }
				onToggleCollapse={ handleToggleCollapse }
			/>
		</div>
	);
}

/**
 * Get a human-readable summary of a category filter.
 *
 * @param {Object} filter The category filter object.
 * @return {string} Summary text.
 */
export function getCategoryFilterSummary( filter ) {
	const values = Array.isArray( filter.value ) ? filter.value : [];
	if ( 0 === values.length ) {
		return '...';
	}
	return sprintf(
		_n(
			/* translators: %d: number of selected categories */
			'%d category',
			'%d categories',
			values.length,
			'rawtype-order-exporter-woocommerce',
		),
		values.length,
	);
}
