import apiFetch from '@wordpress/api-fetch';
import { decodeEntities } from '@wordpress/html-entities';
import { addQueryArgs } from '@wordpress/url';
import { __ } from '@wordpress/i18n';
import { createHigherOrderComponent } from '@wordpress/compose';
import { Fragment, useEffect, useState, useMemo } from '@wordpress/element';
import { InspectorControls } from '@wordpress/block-editor';
import {
	ComboboxControl,
	PanelBody,
	SelectControl,
	Spinner,
} from '@wordpress/components';
import { addFilter } from '@wordpress/hooks';

const FILTER_NAMESPACE = 'ambassadorhub/query-loop-hierarchy-filter';

const HIERARCHY_OPTIONS = [
	{ label: __( 'All items', 'ambassadorhub' ), value: 'all' },
	{ label: __( 'Top-level only', 'ambassadorhub' ), value: 'parents_only' },
	{ label: __( 'Children only', 'ambassadorhub' ), value: 'children_only' },
	{ label: __( 'Children of current post', 'ambassadorhub' ), value: 'current' },
	{ label: __( 'Parent of current post', 'ambassadorhub' ), value: 'parent_of_current' },
	{ label: __( 'Children of specific post', 'ambassadorhub' ), value: 'specific' },
];

/**
 * Register hierarchyFilter and hierarchyParentId as top-level attributes on
 * core/query. These are stored in the block comment alongside the native
 * `query` object and are propagated to child blocks via providesContext
 * (extended on the PHP side via register_block_type_args).
 */
const DEFAULT_ATTRIBUTES = {
	hierarchyFilter: {
		type: 'string',
		default: 'all',
	},
	hierarchyParentId: {
		type: 'integer',
		default: 0,
	},
};

const addHierarchyAttributes = ( settings, name ) => {
	if ( name !== 'core/query' ) {
		return settings;
	}

	return {
		...settings,
		attributes: {
			...settings.attributes,
			...DEFAULT_ATTRIBUTES,
		},
	};
};

addFilter(
	'blocks.registerBlockType',
	FILTER_NAMESPACE,
	addHierarchyAttributes
);

const HierarchyInspector = ( { attributes, setAttributes } ) => {
	const hierarchyFilter = attributes.hierarchyFilter || 'all';
	const hierarchyParentId = Number( attributes.hierarchyParentId || 0 );
	const postType = attributes?.query?.postType || 'post';
	const shouldLoadParentOptions = hierarchyFilter === 'specific' && !! postType;
	const [ options, setOptions ] = useState( [] );
	const [ isLoading, setIsLoading ] = useState( false );
	const [ filterValue, setFilterValue ] = useState( '' );

	useEffect( () => {
		if ( ! shouldLoadParentOptions ) {
			setOptions( [] );
			return;
		}

		let isMounted = true;

		setIsLoading( true );

		apiFetch( {
			path: addQueryArgs( `/wp/v2/${ postType }`, {
				per_page: 50,
				orderby: 'title',
				order: 'asc',
				_fields: 'id,title',
			} ),
		} )
			.then( ( posts ) => {
				if ( ! isMounted ) {
					return;
				}

				const nextOptions = Array.isArray( posts )
					? posts.map( ( post ) => ( {
						label: decodeEntities( post?.title?.rendered || String( post?.title || __( '(no title)', 'ambassadorhub' ) ) ),
						value: String( post.id ),
					} ) )
					: [];

				setOptions( nextOptions );

				if ( hierarchyParentId > 0 && ! nextOptions.some( ( option ) => Number( option.value ) === hierarchyParentId ) ) {
					setAttributes( { hierarchyParentId: 0 } );
				}
			} )
			.catch( () => {
				if ( isMounted ) {
					setOptions( [] );
				}
			} )
			.finally( () => {
				if ( isMounted ) {
					setIsLoading( false );
				}
			} );

		return () => {
			isMounted = false;
		};
	}, [ hierarchyFilter, hierarchyParentId, postType, setAttributes, shouldLoadParentOptions ] );

	const filteredOptions = useMemo( () => {
		if ( ! filterValue ) {
			return options;
		}
		const lower = filterValue.toLowerCase();
		return options.filter( ( option ) => option.label.toLowerCase().includes( lower ) );
	}, [ filterValue, options ] );

	return (
		<InspectorControls>
			<PanelBody title={ __( 'Hierarchy', 'ambassadorhub' ) } initialOpen={ true }>
				<SelectControl
					label={ __( 'Filter items by hierarchy', 'ambassadorhub' ) }
					value={ hierarchyFilter }
					options={ HIERARCHY_OPTIONS }
					onChange={ ( value ) =>
						setAttributes( {
							hierarchyFilter: value,
							hierarchyParentId: value === 'specific' ? hierarchyParentId : 0,
						} )
					}
					__nextHasNoMarginBottom
					__next40pxDefaultSize
				/>

				{ hierarchyFilter === 'specific' && (
					<Fragment>
						{ isLoading && <Spinner /> }
						<ComboboxControl
							label={ __( 'Parent post', 'ambassadorhub' ) }
							value={ hierarchyParentId > 0 ? String( hierarchyParentId ) : '' }
							options={ filteredOptions }
							onFilterValueChange={ ( value ) => setFilterValue( value ) }
							onChange={ ( value ) =>
								setAttributes( {
									hierarchyParentId: parseInt( value, 10 ) || 0,
								} )
							}
							help={ __( 'Choose the parent post whose direct children should be shown.', 'ambassadorhub' ) }
							__next40pxDefaultSize
							__nextHasNoMarginBottom
						/>
					</Fragment>
				) }
			</PanelBody>
		</InspectorControls>
	);
};

const withHierarchyInspectorControls = createHigherOrderComponent( ( BlockEdit ) => {
	return ( props ) => {
		if ( props.name !== 'core/query' ) {
			return <BlockEdit { ...props } />;
		}

		return (
			<Fragment>
				<BlockEdit { ...props } />
				<HierarchyInspector
					attributes={ props.attributes }
					setAttributes={ props.setAttributes }
				/>
			</Fragment>
		);
	};
}, 'withHierarchyInspectorControls' );

addFilter(
	'editor.BlockEdit',
	FILTER_NAMESPACE,
	withHierarchyInspectorControls
);
