/**
 * External dependencies
 */
import {
	InspectorControls,
	useBlockProps,
	store as blockEditorStore,
	useInnerBlocksProps,
} from '@wordpress/block-editor';
import { SelectControl } from '@wordpress/components';
import { store as coreStore } from '@wordpress/core-data';
import { useSelect, useDispatch } from '@wordpress/data';
import { useEffect, useCallback } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import QueryInspectorControls from './inspector-controls';
import { htmlElementMessages } from '@spectra-pro-helpers/loop-builder';
import { TEMPLATE } from './template';

/**
 * Default number of posts per page.
 *
 * Used as a fallback when no site-wide or block-specific value is set.
 *
 * @since x.x.x
 * @type {number}
 */
const DEFAULTS_POSTS_PER_PAGE = 12;

/**
 * Renders a query block that fetches and displays content based on specified attributes.
 *
 * @param {Object} props The element props.
 * @since x.x.x
 * @return {Element} Element to render.
 */
const QueryContent = ( props ) => {
	const { attributes, setAttributes, clientId, name } = props;
	const {
		query, // Query object containing fetch parameters.
		tagName: TagName = 'div', // HTML tag to wrap the block (default: div).
	} = attributes;

	// Mark changes as non-persistent.
	const { __unstableMarkNextChangeAsNotPersistent } = useDispatch( blockEditorStore );

	const blockProps = useBlockProps();

	const innerBlocksProps = useInnerBlocksProps( blockProps, {
		template: TEMPLATE,
	} );

	// Fetch the posts per page setting from site settings or block editor defaults.
	const { postsPerPage } = useSelect( ( select ) => {
		const { getSettings } = select( blockEditorStore );
		const { getEntityRecord, getEntityRecordEdits, canUser } = select( coreStore );

		// Check if the user can read site settings.
		const settingPerPage = canUser( 'read', {
			kind: 'root',
			name: 'site',
		} )
			? +getEntityRecord( 'root', 'site' )?.posts_per_page
			: +getSettings().postsPerPage;

		// Check for any unsaved edits to the site settings.
		const editedSettingPerPage = +getEntityRecordEdits( 'root', 'site' )?.posts_per_page;

		return {
			postsPerPage: editedSettingPerPage || settingPerPage || DEFAULTS_POSTS_PER_PAGE,
		};
	}, [] );

	// Callback to update the query object in attributes.
	const updateQuery = useCallback( ( newQuery ) => setAttributes( { query: { ...query, ...newQuery } } ), [
		query,
		setAttributes,
	] );

	// Synchronize posts per page setting with template context.
	useEffect( () => {
		const newQuery = {};

		// If no perPage is set, apply the site default.
		if ( ! query.perPage && postsPerPage ) {
			newQuery.perPage = postsPerPage;
		}

		// Apply updates if any changes are needed.
		if ( !! Object.keys( newQuery ).length ) {
			__unstableMarkNextChangeAsNotPersistent();
			updateQuery( newQuery );
		}
	}, [ query.perPage, postsPerPage, __unstableMarkNextChangeAsNotPersistent, updateQuery ] );

	return (
		<>
			{ /* Main inspector panel for query settings */ }
			<InspectorControls>
				<QueryInspectorControls
					name={ name }
					attributes={ attributes }
					setQuery={ updateQuery }
					setAttributes={ setAttributes }
					clientId={ clientId }
				/>
			</InspectorControls>

			{ /* Advanced settings panel */ }
			<InspectorControls group="advanced">
				<SelectControl
					__nextHasNoMarginBottom
					__next40pxDefaultSize
					label={ __( 'HTML element', 'spectra-pro' ) }
					options={ [
						{
							label: __( 'Default (<div>)', 'spectra-pro' ),
							value: 'div',
						},
						{ label: '<main>', value: 'main' },
						{ label: '<section>', value: 'section' },
						{ label: '<aside>', value: 'aside' },
					] }
					value={ TagName }
					onChange={ ( value ) => setAttributes( { tagName: value } ) }
					help={ htmlElementMessages[ TagName ] }
				/>
			</InspectorControls>
			<TagName { ...innerBlocksProps } />
		</>
	);
};

export default QueryContent;
