/**
 * RSM suite Gutenberg block inserter branding.
 *
 * @package Rsmspark_Suite
 */
( function ( wp ) {
	'use strict';

	if ( ! wp || ! wp.element || ! wp.blocks ) {
		return;
	}

	var el = wp.element.createElement;
	var addFilter = wp.hooks && wp.hooks.addFilter;
	var addAction = wp.hooks && wp.hooks.addAction;
	var updateCategory = wp.blocks.updateCategory;
	var registerBlockType = wp.blocks.registerBlockType;
	var unregisterBlockType = wp.blocks.unregisterBlockType;
	var getBlockType = wp.blocks.getBlockType;
	var getBlockTypes = wp.blocks.getBlockTypes;
	var domReady = wp.domReady;
	var subscribe = wp.data && wp.data.subscribe;

	var BRAND_ORANGE = '#FF6B35';
	var BRAND_BACKGROUND = '#FFFFFF';
	var BRAND_ICON_COLOR = BRAND_ORANGE;
	var CATEGORY_SLUG = 'rsm-spark';
	var CATEGORY_TITLE = 'RSM Spark';
	var categoryIconApplied = false;
	var domObserver = null;

	/**
	 * @return {import('react').ReactElement}
	 */
	function sparkCategoryIcon() {
		return el(
			'svg',
			{
				xmlns: 'http://www.w3.org/2000/svg',
				viewBox: '0 0 24 24',
				width: 24,
				height: 24,
				'aria-hidden': true,
				focusable: 'false',
			},
			el( 'path', {
				fill: BRAND_ORANGE,
				d: 'M13 2 4 14h7l-1 8 9-12h-7l1-8z',
			} )
		);
	}

	/**
	 * @param {string} icon Icon slug or dashicon class string.
	 * @return {string}
	 */
	function normalizeDashiconSlug( icon ) {
		return String( icon || 'admin-plugins' )
			.replace( /^dashicons\s+dashicons-/, '' )
			.replace( /^dashicons-/, '' );
	}

	/**
	 * @param {*} icon Block icon value.
	 * @return {string}
	 */
	function extractIconSlug( icon ) {
		if ( typeof icon === 'string' ) {
			return normalizeDashiconSlug( icon );
		}

		if ( icon && typeof icon === 'object' ) {
			if ( typeof icon.src === 'string' ) {
				return normalizeDashiconSlug( icon.src );
			}

			if (
				icon.src &&
				typeof icon.src === 'object' &&
				icon.src.props &&
				typeof icon.src.props.className === 'string'
			) {
				return normalizeDashiconSlug( icon.src.props.className );
			}
		}

		return 'admin-plugins';
	}

	/**
	 * @param {*} icon Block icon value.
	 * @return {boolean}
	 */
	function isBrandedIcon( icon ) {
		return (
			icon &&
			typeof icon === 'object' &&
			icon.background === BRAND_BACKGROUND &&
			icon.foreground === BRAND_ICON_COLOR &&
			icon.src
		);
	}

	/**
	 * Orange dashicon on white tile (RSMSpark brand — not white-on-orange).
	 *
	 * @param {string} iconSlug Dashicon slug.
	 * @return {{ background: string, foreground: string, src: import('react').ReactElement }}
	 */
	function rsmDashiconIcon( iconSlug ) {
		var slug = normalizeDashiconSlug( iconSlug );

		return {
			background: BRAND_BACKGROUND,
			foreground: BRAND_ICON_COLOR,
			src: el( 'span', {
				className: 'dashicons dashicons-' + slug,
				style: {
					color: BRAND_ICON_COLOR,
					fontSize: '20px',
					height: '20px',
					width: '20px',
				},
				'aria-hidden': true,
			} ),
		};
	}

	/**
	 * @param {import('react').ReactElement} svgElement SVG element.
	 * @return {{ background: string, foreground: string, src: import('react').ReactElement }}
	 */
	function rsmSvgIcon( svgElement ) {
		return {
			background: BRAND_BACKGROUND,
			foreground: BRAND_ICON_COLOR,
			src: svgElement,
		};
	}

	/**
	 * @param {string} blockName Block name.
	 * @return {boolean}
	 */
	function isSowbRsmBlockName( blockName ) {
		if ( typeof blockName !== 'string' || '' === blockName ) {
			return false;
		}

		return (
			0 === blockName.indexOf( 'sowb/rsm-content-widgets-' ) ||
			0 === blockName.indexOf( 'sowb/rsm-cw-' )
		);
	}

	/**
	 * @param {string} sowbName SOWB block name.
	 * @return {string}
	 */
	function sowbToNativeBlockName( sowbName ) {
		var match = /^sowb\/rsm-content-widgets-(.+)-widget$/.exec( sowbName || '' );
		return match ? 'rsm-content-widgets/' + match[ 1 ] : '';
	}

	/**
	 * @param {string} blockName Block name.
	 * @return {boolean}
	 */
	function isRsmBlockName( blockName ) {
		if ( typeof blockName !== 'string' || '' === blockName ) {
			return false;
		}

		return (
			0 === blockName.indexOf( 'rsm-' ) ||
			0 === blockName.indexOf( 'rsm/' ) ||
			0 === blockName.indexOf( 'openrsm/' ) ||
			blockName === 'core/columns/rsmspark-layout-row' ||
			blockName === 'core/columns/rsm-layout-row' ||
			isSowbRsmBlockName( blockName )
		);
	}

	/**
	 * @param {string|undefined} category Block category slug.
	 * @param {string} blockName Block name.
	 * @return {boolean}
	 */
	function shouldBrandBlock( category, blockName ) {
		return category === CATEGORY_SLUG || isRsmBlockName( blockName );
	}

	/**
	 * @param {string} blockName Block name.
	 * @param {*} fallbackIcon Existing icon value.
	 * @return {*}
	 */
	function brandedIconForBlock( blockName, fallbackIcon ) {
		if ( isSowbRsmBlockName( blockName ) ) {
			var nativeName = sowbToNativeBlockName( blockName );
			if ( nativeName && typeof getBlockType === 'function' ) {
				var nativeType = getBlockType( nativeName );
				if ( nativeType && nativeType.icon ) {
					return brandIconValue( nativeType.icon );
				}
			}
			return rsmDashiconIcon( 'admin-plugins' );
		}

		return brandIconValue( fallbackIcon || 'admin-plugins' );
	}

	/**
	 * @param {*} icon Existing icon value.
	 * @return {*}
	 */
	function brandIconValue( icon ) {
		if ( isBrandedIcon( icon ) ) {
			return icon;
		}

		return rsmDashiconIcon( extractIconSlug( icon ) );
	}

	/**
	 * @param {Object} settings Block or variation settings.
	 * @param {string} blockName Block name.
	 * @return {Object}
	 */
	function applyBrandingToSettings( settings, blockName ) {
		if ( ! settings || typeof settings !== 'object' ) {
			return settings;
		}

		if ( ! shouldBrandBlock( settings.category, blockName ) ) {
			return settings;
		}

		var next = Object.assign( {}, settings, {
			category: CATEGORY_SLUG,
			icon: brandedIconForBlock( blockName, settings.icon ),
		} );

		return next;
	}

	/**
	 * @param {string} blockName Block name.
	 * @return {void}
	 */
	function patchBlockTypeIcon( blockName ) {
		if (
			typeof blockName !== 'string' ||
			typeof getBlockType !== 'function' ||
			typeof registerBlockType !== 'function'
		) {
			return;
		}

		var blockType = getBlockType( blockName );
		if ( ! blockType || ! shouldBrandBlock( blockType.category, blockName ) ) {
			return;
		}

		if ( isBrandedIcon( blockType.icon ) ) {
			return;
		}

		var next = Object.assign( {}, blockType, {
			category: CATEGORY_SLUG,
			icon: brandedIconForBlock( blockName, blockType.icon ),
		} );

		if ( typeof unregisterBlockType === 'function' ) {
			unregisterBlockType( blockName );
		}

		registerBlockType( blockName, next );
	}

	/**
	 * @return {void}
	 */
	function patchAllRegisteredBlockIcons() {
		if ( typeof getBlockTypes !== 'function' ) {
			return;
		}

		getBlockTypes().forEach( function ( blockType ) {
			patchBlockTypeIcon( blockType.name );
		} );
	}

	/**
	 * @param {string} title Block title in inserter.
	 * @return {boolean}
	 */
	function isRsmInserterTitle( title ) {
		var value = String( title || '' ).trim();
		if ( ! value ) {
			return false;
		}

		return (
			/^RSM\b/i.test( value ) ||
			/\bRSMSpark\b/i.test( value ) ||
			/^Popup trigger\b/i.test( value ) ||
			/^Job\b/i.test( value ) ||
			/^Careers\b/i.test( value ) ||
			/^Application received\b/i.test( value )
		);
	}

	/**
	 * Paint orange glyphs in the inserter when registry icons are still block-default.
	 *
	 * @return {void}
	 */
	function brandInserterDomIcons() {
		if ( typeof document === 'undefined' || ! document.querySelectorAll ) {
			return;
		}

		document
			.querySelectorAll( '.block-editor-block-types-list__item' )
			.forEach( function ( item ) {
				var titleEl = item.querySelector(
					'.block-editor-block-types-list__item-title'
				);
				if ( ! titleEl || ! isRsmInserterTitle( titleEl.textContent ) ) {
					return;
				}

				var iconEl = item.querySelector(
					'.block-editor-block-types-list__item-icon'
				);
				if ( ! iconEl ) {
					return;
				}

				iconEl.classList.add( 'rsm-branded-inserter-icon' );
				iconEl.style.backgroundColor = BRAND_BACKGROUND;
				iconEl.style.color = BRAND_ICON_COLOR;

				iconEl.querySelectorAll( '.dashicons' ).forEach( function ( glyph ) {
					glyph.style.color = BRAND_ICON_COLOR;
				} );

				iconEl.querySelectorAll( 'svg' ).forEach( function ( svg ) {
					svg.style.color = BRAND_ICON_COLOR;
					svg.style.fill = BRAND_ICON_COLOR;
				} );
			} );
	}

	function ensureDomObserver() {
		if ( domObserver || typeof window.MutationObserver === 'undefined' ) {
			return;
		}

		var root =
			document.querySelector( '.block-editor-inserter__menu' ) ||
			document.querySelector( '.interface-interface-skeleton__sidebar' ) ||
			document.querySelector( '.interface-interface-skeleton__body' ) ||
			document.body;

		if ( ! root ) {
			return;
		}

		domObserver = new window.MutationObserver( function () {
			brandInserterDomIcons();
			brandBlockToolbarDom();
		} );
		domObserver.observe( root, { childList: true, subtree: true } );
	}

	/**
	 * Orange block icon in the floating block toolbar (selected block).
	 *
	 * @return {void}
	 */
	function brandBlockToolbarDom() {
		if ( typeof document === 'undefined' ) {
			return;
		}

		var toolbar = document.querySelector( '.block-editor-block-toolbar' );
		if ( ! toolbar ) {
			return;
		}

		var blockName = '';
		if ( wp.data && typeof wp.data.select === 'function' ) {
			try {
				var selected = wp.data.select( 'core/block-editor' ).getSelectedBlock();
				blockName = selected && selected.name ? selected.name : '';
			} catch ( e ) {
				blockName = '';
			}
		}

		var shouldBrand = shouldBrandBlock( null, blockName );
		toolbar.classList.toggle( 'rsmspark-block-toolbar-branded', shouldBrand );

		if ( ! shouldBrand ) {
			return;
		}

		toolbar.querySelectorAll( '.block-editor-block-icon .dashicons' ).forEach(
			function ( glyph ) {
				glyph.style.color = BRAND_ICON_COLOR;
			}
		);

		toolbar.querySelectorAll( '.block-editor-block-icon svg' ).forEach(
			function ( svg ) {
				svg.style.color = BRAND_ICON_COLOR;
				svg.style.fill = BRAND_ICON_COLOR;
			}
		);

		toolbar
			.querySelectorAll(
				'.block-editor-block-switcher__toggle, .components-button.block-editor-block-switcher__toggle'
			)
			.forEach( function ( button ) {
				button.style.color = BRAND_ICON_COLOR;
			} );
	}

	function applyCategoryIcon() {
		if ( categoryIconApplied || typeof updateCategory !== 'function' ) {
			return;
		}

		updateCategory( CATEGORY_SLUG, {
			icon: sparkCategoryIcon(),
		} );
		categoryIconApplied = true;
	}

	function runBrandingPasses() {
		applyCategoryIcon();
		patchAllRegisteredBlockIcons();
		brandInserterDomIcons();
		brandBlockToolbarDom();
		ensureDomObserver();
	}

	if ( addFilter ) {
		addFilter(
			'blocks.registerBlockType',
			'rsm/block-inserter-branding',
			function ( settings, blockName ) {
				return applyBrandingToSettings( settings, blockName );
			},
			1
		);

		addFilter(
			'blocks.registerBlockVariation',
			'rsm/block-variation-branding',
			function ( settings, blockName ) {
				if ( blockName !== 'core/columns' && blockName !== 'core/group' ) {
					return settings;
				}

				if (
					! settings ||
					( settings.name !== 'rsmspark-layout-row' && settings.name !== 'rsm-layout-row' )
				) {
					return settings;
				}

				return applyBrandingToSettings(
					settings,
					settings.name === 'rsmspark-layout-row'
						? 'core/columns/rsmspark-layout-row'
						: 'core/columns/rsm-layout-row'
				);
			},
			1
		);
	}

	if ( addAction ) {
		addAction( 'blocks.registerBlockType', 'rsm/patch-block-icon', patchBlockTypeIcon, 20 );
	}

	runBrandingPasses();

	if ( typeof window.setTimeout === 'function' ) {
		window.setTimeout( runBrandingPasses, 0 );
		window.setTimeout( runBrandingPasses, 100 );
		window.setTimeout( runBrandingPasses, 500 );
		window.setTimeout( runBrandingPasses, 1500 );
	}

	if ( typeof domReady === 'function' ) {
		domReady( runBrandingPasses );
	}

	if ( typeof subscribe === 'function' ) {
		var unsubscribe = subscribe( function () {
			patchAllRegisteredBlockIcons();
			brandInserterDomIcons();
			brandBlockToolbarDom();
		} );

		if ( typeof window.setTimeout === 'function' ) {
			window.setTimeout( function () {
				if ( typeof unsubscribe === 'function' ) {
					unsubscribe();
				}
			}, 10000 );
		}
	}

	window.RSMBlockBranding = {
		BRAND_ORANGE: BRAND_ORANGE,
		BRAND_BACKGROUND: BRAND_BACKGROUND,
		BRAND_ICON_COLOR: BRAND_ICON_COLOR,
		CATEGORY_SLUG: CATEGORY_SLUG,
		CATEGORY_TITLE: CATEGORY_TITLE,
		rsmDashiconIcon: rsmDashiconIcon,
		rsmSvgIcon: rsmSvgIcon,
		brandIconValue: brandIconValue,
		applyCategoryIcon: applyCategoryIcon,
		patchAllRegisteredBlockIcons: patchAllRegisteredBlockIcons,
		brandInserterDomIcons: brandInserterDomIcons,
		brandBlockToolbarDom: brandBlockToolbarDom,
		isSowbRsmBlockName: isSowbRsmBlockName,
		sowbToNativeBlockName: sowbToNativeBlockName,
	};
} )( window.wp );
