/**
 * External dependencies.
 */
import { createHigherOrderComponent } from '@wordpress/compose';
import { applyFilters } from '@wordpress/hooks';

/**
 * Internal dependencies.
 */
import { spectraClassNames } from '@spectra-helpers';

/**
 * Array of blocks that should be excluded from Global Styles.
 *
 * @since x.x.x
 *
 * @member {Array} EXCLUDED_BLOCKS An array of blocks that should be excluded.
 */
export const EXCLUDED_BLOCKS = applyFilters( 'spectra.excludesGS', ['spectra/popup-builder'] );

/**
 * Array of blocks that support Global Styles.
 *
 * @since x.x.x
 *
 * @member {Array} SUPPORTED_BLOCKS An array of blocks that should be supported.
 */
export const SUPPORTED_BLOCKS = applyFilters( 'spectra.supportsGS', [] );

/**
 * Check if a block is allowed for the Global Styles.
 *
 * @since x.x.x
 *
 * @param {Object}  block      The block object
 * @param {boolean} returnType Whether to return the block type instead of boolean
 * @return {boolean|string} Whether the block is allowed or the block type
 */
export const isAllowedBlock = ( block, returnType = false ) => {
	if ( ! block?.name ) {
		return false;
	}

	// Check if block is excluded.
	if ( EXCLUDED_BLOCKS.includes( block.name ) ) {
		return false;
	}

	// Define allowed block prefixes.
	const ALLOWED_PREFIXES = [ 'spectra/', 'spectra-pro/' ];

	// Check if the block is allowed.
	const isAllowed = (
		ALLOWED_PREFIXES.some( ( prefix ) => block.name.startsWith( prefix ) ) ||
		SUPPORTED_BLOCKS.includes( block.name )
	);

	if ( ! isAllowed ) {
		return false;
	}

	if ( returnType ) {
		if ( block.name.startsWith( 'spectra/' ) ) {
			return 'spectra';
		}
		if ( block.name.startsWith( 'spectra-pro/' ) ) {
			return 'spectra-pro';
		}
		return 'other';
	}

	return true;
};

/**
 * Extends block settings with the Global Styles attribute.
 *
 * @since x.x.x
 *
 * @param {Object} settings - The original block settings object.
 * @param {string} name     - The name of the block.
 * @return {Object} Modified block settings with animation attributes added.
 */
export const extendBlockAttributes = ( settings, name ) => {
	const blockType = isAllowedBlock( { name }, true );
	if ( ! blockType ) {
		return settings;
	}

	// Ensure settings.attributes exists
	const existingAttributes = settings.attributes || {};

	// Get default CSS class for Spectra/Spectra Pro blocks  
	let defaultClasses = [];
	if ( blockType === 'spectra' || blockType === 'spectra-pro' ) {
		const defaultClass = getDefaultClassForBlock( name );
		if ( defaultClass ) {
			// Always add the default-[blockname] class for supported blocks
			defaultClasses = [ defaultClass ];
		}
	}

	return {
		...settings,
		attributes: {
			...existingAttributes,
			spectraGSClasses: {
				type: 'array',
				default: defaultClasses,
			},
		},
	};
};

/**
 * Add the Global Style classes to all supported blocks.
 *
 * @since x.x.x
 *
 * @param {Function} BlockListBlock - The original BlockListBlock component.
 * @return {Function} Enhanced Block from the BlockListBlock component with the applied Global Styles.
 */
export const addGSClasses = createHigherOrderComponent( ( BlockListBlock ) => ( ( props ) => {
	const {
		name,
		attributes: {
			spectraGSClasses = [],
		}
	} = props;

	if ( ! isAllowedBlock( { name } ) ) {
		return <BlockListBlock { ...props }/>;
	}

	return <BlockListBlock { ...props } className={ spectraClassNames( spectraGSClasses ) } />;
} ), 'addGSClasses' );

/**
 * Gets the default class for a given block name.
 *
 * @since x.x.x
 *
 * @param {string} blockName - The block name (e.g., 'spectra/button').
 * @return {string|null} The default class name or null if none exists.
 */
const getDefaultClassForBlock = ( blockName ) => {
	// Block name to default class mapping
	const blockDefaultClassMapping = {
		'spectra/button': 'default-button',
		'spectra/buttons': 'default-buttons',
		'spectra/container': 'default-container',
		'spectra/content': 'default-content',
		'spectra/google-map': 'default-google-map',
		'spectra/icon': 'default-icon',
		'spectra/icons': 'default-icons',
		'spectra/separator': 'default-separator',
		'spectra/list': 'default-list',
		'spectra/list-child-item': 'default-list-child-item',
		'spectra/list-child-icon': 'default-list-child-icon',
		'spectra/tabs': 'default-tabs',
		'spectra/tabs-child-tab-wrapper': 'default-tabs-child-tab-wrapper',
		'spectra/tabs-child-tab-button': 'default-tabs-child-tab-button',
		'spectra/tabs-child-tabpanel': 'default-tabs-child-tabpanel',
		'spectra/accordion': 'default-accordion',
		'spectra/accordion-child-item': 'default-accordion-child-item',
		'spectra/accordion-child-header': 'default-accordion-child-header',
		'spectra/accordion-child-details': 'default-accordion-child-details',
		'spectra/accordion-child-header-content': 'default-accordion-child-header-content',
		'spectra/accordion-child-header-icon': 'default-accordion-child-header-icon',
		'spectra/slider': 'default-slider',
		'spectra/slider-child': 'default-slider-child',
		'spectra/countdown': 'default-countdown',
		'spectra/countdown-child-day': 'default-countdown-child-day',
		'spectra/countdown-child-hour': 'default-countdown-child-hour',
		'spectra/countdown-child-minute': 'default-countdown-child-minute',
		'spectra/countdown-child-second': 'default-countdown-child-second',
		'spectra/countdown-child-number': 'default-countdown-child-number',
		'spectra/countdown-child-label': 'default-countdown-child-label',
		'spectra/countdown-child-separator': 'default-countdown-child-separator',
		'spectra/countdown-child-expiry-wrapper': 'default-countdown-child-expiry-wrapper',
		'spectra/modal': 'default-modal',
		'spectra/modal-child-trigger': 'default-modal-child-trigger',
		'spectra/modal-child-button': 'default-modal-child-button',
		'spectra/modal-child-content': 'default-modal-child-content',
		'spectra/modal-child-icon': 'default-modal-child-icon',
		'spectra/modal-popup': 'default-modal-popup',
		'spectra/modal-child-popup-close-icon': 'default-modal-child-popup-close-icon',
		'spectra/modal-popup-content': 'default-modal-popup-content',
		'spectra-pro/loop-builder': 'default-loop-builder',
		'spectra-pro/loop-builder-child-search': 'default-loop-builder-child-search',
		'spectra-pro/loop-builder-child-filter': 'default-loop-builder-child-filter',
		'spectra-pro/loop-builder-child-filter-select': 'default-loop-builder-child-filter-select',
		'spectra-pro/loop-builder-child-filter-checkbox': 'default-loop-builder-child-filter-checkbox',
		'spectra-pro/loop-builder-child-filter-button': 'default-loop-builder-child-filter-button',
		'spectra-pro/loop-builder-child-reset-all-button': 'default-loop-builder-child-reset-all-button',
		'spectra-pro/loop-builder-child-sort': 'default-loop-builder-child-sort',
		'spectra-pro/loop-builder-child-template': 'default-loop-builder-child-template',
		'spectra-pro/loop-builder-child-pagination': 'default-loop-builder-child-pagination',
		'spectra-pro/loop-builder-child-pagination-previous-button': 'default-loop-builder-child-pagination-previous-button',
		'spectra-pro/loop-builder-child-pagination-page-numbers-button': 'default-loop-builder-child-pagination-page-numbers-button',
		'spectra-pro/loop-builder-child-pagination-next-button': 'default-loop-builder-child-pagination-next-button',
		'spectra-pro/loop-builder-child-no-results': 'default-loop-builder-child-no-results',
	};

	return blockDefaultClassMapping[ blockName ] || null;
};


/**
 * Recursively applies default classes to nested blocks when they are created.
 *
 * @since x.x.x
 *
 * @param {Object} block - The block object.
 * @return {Object} Block object with default classes applied to nested blocks.
 */
export const applyDefaultsToNestedBlocks = ( block ) => {
	// Apply defaults to the current block if it supports them
	const blockType = isAllowedBlock( { name: block.name }, true );
	if ( blockType === 'spectra' || blockType === 'spectra-pro' ) {
		const defaultClass = getDefaultClassForBlock( block.name );
		if ( defaultClass ) {
			// Ensure attributes exist
			if ( ! block.attributes ) {
				block.attributes = {};
			}
			
			// Only set defaults if spectraGSClasses doesn't exist or is empty
			if ( ! block.attributes.spectraGSClasses || block.attributes.spectraGSClasses.length === 0 ) {
				block.attributes.spectraGSClasses = [ defaultClass ];
			}
		}
	}
	
	// Recursively apply to inner blocks
	if ( block.innerBlocks && Array.isArray( block.innerBlocks ) ) {
		block.innerBlocks = block.innerBlocks.map( applyDefaultsToNestedBlocks );
	}
	
	return block;
};

