/**
 * External dependencies
 */
import classnames from 'classnames';

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
import {
	useBlockProps,
	useInnerBlocksProps,
	__experimentalRecursionProvider as RecursionProvider,
	__experimentalUseHasRecursion as useHasRecursion,
	Warning,
	store as blockEditorStore,
} from '@wordpress/block-editor';
import { useEntityProp, useEntityBlockEditor } from '@wordpress/core-data';
import { useSelect, useDispatch } from '@wordpress/data';
import { Placeholder, Button } from '@wordpress/components';
import { postContent as icon } from '@wordpress/icons';
import { createBlock } from '@wordpress/blocks';

/**
 * Internal dependencies
 */
import { useCanEditEntity } from '../utils/hooks';

function ReadOnlyContent( {
	layoutClassNames,
	userCanEdit,
	postType,
	postId,
} ) {
	const [ , , content ] = useEntityProp(
		'postType',
		postType,
		'content',
		postId
	);
	const blockProps = useBlockProps( { className: layoutClassNames } );
	return content?.protected && ! userCanEdit ? (
		<div { ...blockProps }>
			<Warning>{ __( 'This content is password protected.' ) }</Warning>
		</div>
	) : (
		<div
			{ ...blockProps }
			dangerouslySetInnerHTML={ { __html: content?.rendered } }
		></div>
	);
}

function EmptyContentPlaceholder( { context, onClose, openInserter } ) {
	const { postType } = context;
	const label =
		'page' === postType
			? __( 'This page’s content is empty' )
			: __( 'This post’s content is empty' );
	return (
		<Placeholder
			icon={ icon }
			label={ label }
			instructions={ __(
				'Add your first block or pattern to get started.'
			) }
		>
			<Button variant="primary" onClick={ openInserter }>
				{ __( 'Choose a pattern' ) }
			</Button>

			<Button variant="secondary" onClick={ onClose }>
				{ __( 'Start blank' ) }
			</Button>
		</Placeholder>
	);
}

function PostContentPlaceholder( { layoutClassNames } ) {
	const blockProps = useBlockProps( { className: layoutClassNames } );
	return (
		<div { ...blockProps }>
			<Placeholder
				className="wp-block-post-content__content-placeholder"
				withIllustration
			>
				<p>
					{ __( 'This block will be replaced with your content.' ) }
				</p>
			</Placeholder>
		</div>
	);
}

function EditableContent( { context = {}, clientId } ) {
	const { postType, postId } = context;
	const { selectBlock, insertBlock } = useDispatch( blockEditorStore );
	const [ blocks, onInput, onChange ] = useEntityBlockEditor(
		'postType',
		postType,
		{ id: postId }
	);

	const setInserterIsOpened = useSelect(
		( select ) =>
			select( blockEditorStore ).getSettings()
				.__experimentalSetIsInserterOpened,
		[ postType, postId ]
	);

	const hasInnerBlocks = blocks?.length;

	const { children, ...props } = useInnerBlocksProps(
		useBlockProps( {
			className: classnames( 'entry-content', {
				'wp-block-post-content__placeholder': ! hasInnerBlocks,
			} ),
		} ),
		{
			value: blocks,
			onInput,
			onChange,
		}
	);

	const onClose = () => {
		const initialBlock = createBlock( 'core/paragraph' );
		insertBlock( initialBlock, 0, clientId );
		selectBlock( initialBlock.clientId );
	};

	const openInserter = () => {
		setInserterIsOpened( {
			initialTab: 'patterns',
			rootClientId: clientId,
			insertionIndex: 0,
		} );
	};

	return (
		<div { ...props }>
			{ children }
			{ ! hasInnerBlocks && (
				<EmptyContentPlaceholder
					context={ context }
					onClose={ onClose }
					openInserter={ openInserter }
				/>
			) }
		</div>
	);
}

function Content( props ) {
	const { context: { queryId, postType, postId } = {}, layoutClassNames } =
		props;
	const userCanEdit = useCanEditEntity( 'postType', postType, postId );
	if ( userCanEdit === undefined ) {
		return null;
	}

	const isDescendentOfQueryLoop = Number.isFinite( queryId );
	const isEditable = userCanEdit && ! isDescendentOfQueryLoop;

	return isEditable ? (
		<EditableContent { ...props } />
	) : (
		<ReadOnlyContent
			layoutClassNames={ layoutClassNames }
			userCanEdit={ userCanEdit }
			postType={ postType }
			postId={ postId }
		/>
	);
}

function RecursionError() {
	const blockProps = useBlockProps();
	return (
		<div { ...blockProps }>
			<Warning>
				{ __( 'Block cannot be rendered inside itself.' ) }
			</Warning>
		</div>
	);
}

export default function PostContentEdit( {
	clientId,
	context,
	__unstableLayoutClassNames: layoutClassNames,
} ) {
	const { postId: contextPostId, postType: contextPostType } = context;
	const hasAlreadyRendered = useHasRecursion( contextPostId );

	if ( contextPostId && contextPostType && hasAlreadyRendered ) {
		return <RecursionError />;
	}

	return (
		<RecursionProvider uniqueId={ contextPostId }>
			{ contextPostId && contextPostType ? (
				<Content
					clientId={ clientId }
					context={ context }
					layoutClassNames={ layoutClassNames }
				/>
			) : (
				<PostContentPlaceholder layoutClassNames={ layoutClassNames } />
			) }
		</RecursionProvider>
	);
}