<?php
/**
 * Ensures D4→D5 conversion outlines are registered whenever conversion runs — not only in wp-admin /
 * Visual Builder contexts.
 *
 * @package DiviSupreme
 */

declare(strict_types=1);

namespace DiviSupreme\Includes\Divi5Conversion;

use ET\Builder\Packages\ModuleLibrary\ModuleRegistration;

/**
 * Divi merges conversion outlines onto {@see 'divi.conversion.moduleLibrary.conversionMap'} inside
 * {@see ModuleRegistration::process_conversion_outline()}. Core third-party registration only calls that
 * when `is_admin()` at module load time, or when `divi_visual_builder_before_d4_conversion` runs.
 * The D5 migrator and some portability paths call {@see \ET\Builder\Packages\Conversion\Conversion::maybeConvertContent()}
 * without firing that action — so DSM outlines are missing and legacy shortcodes stay as Shortcode fallback.
 *
 * Bootstrap after all DSM blocks register: scan the block registry and process each outline once.
 */
final class ConversionOutlineBootstrap
{

	/**
	 * @var array<string, true>
	 */
	private static $processed = array();

	/**
	 * @return void
	 */
	public static function register(): void
	{
		// After DSM blocks register on `init` (ModuleRegistration::register_module).
		add_action('init', array(self::class, 'ensure_conversion_maps'), 99);

		add_action('wp_loaded', array(self::class, 'ensure_conversion_maps'), 20);

		add_action(
			'divi_visual_builder_before_d4_conversion',
			array(self::class, 'ensure_conversion_maps'),
			1
		);

		// Bulk migrator / portability may call Conversion::maybeConvertContent without firing
		// `divi_visual_builder_before_d4_conversion`. Lazy-ensure before the map is read.
		add_filter(
			'divi.conversion.moduleLibrary.conversionMap',
			array(self::class, 'ensure_conversion_maps_before_map'),
			1,
			1
		);
	}

	/**
	 * Filter callback: register outlines before Divi reads the conversion map.
	 *
	 * @param array<string, mixed> $conversion_map Conversion map (unused; pass-through).
	 * @return array<string, mixed>
	 */
	public static function ensure_conversion_maps_before_map($conversion_map)
	{
		self::ensure_conversion_maps();

		return is_array($conversion_map) ? $conversion_map : array();
	}

	/**
	 * Register conversion map filters for every `dsm/*` block type that ships a conversion-outline JSON.
	 *
	 * Safe to call multiple times per request (later calls no-op).
	 *
	 * @return void
	 */
	public static function ensure_conversion_maps(): void
	{
		if (! class_exists(ModuleRegistration::class)) {
			return;
		}

		if (! class_exists('WP_Block_Type_Registry')) {
			return;
		}

		$registry = \WP_Block_Type_Registry::get_instance();
		foreach ($registry->get_all_registered() as $block_type) {
			$name = $block_type->name ?? '';
			if (! is_string($name) || ! str_starts_with($name, 'dsm/')) {
				continue;
			}

			if (isset(self::$processed[$name])) {
				continue;
			}

			$conversion_outline_file = apply_filters(
				// phpcs:ignore WordPress.NamingConventions.ValidHookName.NotLowercase -- Divi 5 core uses dot-notation hook names.
				'divi.moduleLibrary.conversion.moduleConversionOutlineFile',
				'',
				$name
			);

			if (! is_string($conversion_outline_file) || '' === $conversion_outline_file) {
				continue;
			}

			if (! is_readable($conversion_outline_file)) {
				continue;
			}

			$metadata = array('name' => $name);
			$ok       = ModuleRegistration::process_conversion_outline($metadata, $conversion_outline_file);
			if ($ok) {
				self::$processed[$name] = true;
			}
		}
	}
}
