/**
 * WordPress dependencies
 */
import { useSelect } from '@safe-wordpress/data';
import { _x, sprintf } from '@safe-wordpress/i18n';

/**
 * External dependencies
 */
import clsx from 'clsx';
import { store as NAB_DATA } from '@nab/data';
import type { EntityId, EntityKindName, Maybe } from '@nab/types';

/**
 * Internal dependencies
 */
import './style.scss';
import { PostOption } from './post-option';
import { useOptionLoader } from '../utils';
import { AsyncSelectControl } from '../../async-select-control';

import type { PostSearcherProps } from '../types';

export const SingularPostSearcher = ( {
	id,
	className,
	disabled,
	onChange,
	placeholder: defaultPlaceholder,
	value,
	type = 'post',
	menuPlacement,
	menuShouldBlockScroll,
	...loaderProps
}: PostSearcherProps< EntityId, Maybe< EntityId > > ): JSX.Element => {
	const { post, isLoading } = usePost( type, value );
	const placeholder = usePlaceholder(
		{ type, id: value },
		defaultPlaceholder
	);

	const label = post?.title;
	const selectedOption =
		! isLoading && value ? { type, value, label: label ?? '' } : undefined;

	const loadOptions = useOptionLoader( { ...loaderProps, type } );

	return (
		<AsyncSelectControl
			id={ id }
			className={ clsx( [
				className,
				{
					'nab-singular-post-searcher': true,
					'nab-singular-post-searcher--is-loading': isLoading,
				},
			] ) }
			components={ { Option: PostOption } }
			disabled={ disabled || isLoading }
			cacheUniqs={ [ type ] }
			loadOptions={ loadOptions }
			value={ selectedOption }
			onChange={ ( option ) => onChange( option?.value ) }
			additional={ { page: 1 } }
			placeholder={ placeholder }
			menuPlacement={ menuPlacement }
			menuShouldBlockScroll={ menuShouldBlockScroll }
		/>
	);
};

// =====
// HOOKS
// =====

const usePost = (
	type: EntityKindName,
	value: EntityId = 0
): {
	readonly post: { readonly id: EntityId; readonly title: string };
	readonly isLoading: boolean;
} => {
	const post = useSelect(
		( select ) =>
			select( NAB_DATA ).getEntityRecord( type, value ) || {
				id: value,
				title: sprintf( getElementNotFound( type ), value ),
			},
		[ type, value ]
	);

	const isLoading = useSelect(
		( select ) =>
			! select( NAB_DATA ).hasFinishedResolution( 'getEntityRecord', [
				type,
				value,
			] ) &&
			! select( NAB_DATA ).hasResolutionFailed( 'getEntityRecord', [
				type,
				value,
			] ),
		[ type, value ]
	);

	return { post, isLoading };
};

function usePlaceholder(
	{ type, id }: { type: EntityKindName; id?: EntityId },
	defaultPlaceholder?: string
): string {
	const { isLoading } = usePost( type, id );
	if ( isLoading ) {
		return _x( 'Loading…', 'text', 'nelio-ab-testing' );
	}

	if ( defaultPlaceholder ) {
		return defaultPlaceholder;
	}

	switch ( type ) {
		case 'page':
			return _x( 'Select a page…', 'user', 'nelio-ab-testing' );
		case 'post':
			return _x( 'Select a post…', 'user', 'nelio-ab-testing' );
		case 'product':
			return _x( 'Select a product…', 'user', 'nelio-ab-testing' );
		default:
			return _x( 'Select…', 'user', 'nelio-ab-testing' );
	}
}

function getElementNotFound( type: EntityKindName ): string {
	switch ( type ) {
		case 'page':
			/* translators: %d: Page id. */
			return _x( 'Page #%d not found', 'text', 'nelio-ab-testing' );
		case 'post':
			/* translators: %d: Post id. */
			return _x( 'Post #%d not found', 'text', 'nelio-ab-testing' );
		case 'product':
			/* translators: %d: Product id. */
			return _x( 'Product #%d not found', 'text', 'nelio-ab-testing' );
		default:
			/* translators: %d: Item id. */
			return _x( 'Content #%d not found', 'text', 'nelio-ab-testing' );
	}
}
