<?php
/**
 * Cache module — Theme Compat Manager
 *
 * Loads every adapter, instantiates those whose target is active and that
 * the user has not disabled, and exposes a single point of contact for the
 * rest of the module (filters for exclusions, summary for the admin UI).
 *
 * @package BlaminhorEssentials
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class Blaminhor_Essentials_Cache_Theme_Compat_Manager {

	/** @var Blaminhor_Essentials_Module_Cache */
	private $parent;

	/** @var Blaminhor_Essentials_Cache_Theme_Compat_Base[] */
	private $registered = array();

	/** @var Blaminhor_Essentials_Cache_Theme_Compat_Base[] */
	private $active = array();

	public function __construct( Blaminhor_Essentials_Module_Cache $parent ) {
		$this->parent = $parent;
		$this->build_registry();
	}

	private function build_registry() {
		$base = __DIR__ . '/';
		require_once $base . 'class-theme-compat-avada.php';
		require_once $base . 'class-theme-compat-elementor.php';
		require_once $base . 'class-theme-compat-divi.php';

		$adapters = array(
			new Blaminhor_Essentials_Cache_Theme_Compat_Avada( $this->parent ),
			new Blaminhor_Essentials_Cache_Theme_Compat_Elementor( $this->parent ),
			new Blaminhor_Essentials_Cache_Theme_Compat_Divi( $this->parent ),
		);
		foreach ( $adapters as $a ) {
			$this->registered[ $a->id() ] = $a;
		}
	}

	/**
	 * Wire active adapters and the shared exclusion filters.
	 */
	public function register_hooks() {
		$disabled = $this->disabled_set();
		foreach ( $this->registered as $id => $adapter ) {
			if ( isset( $disabled[ $id ] ) ) {
				continue;
			}
			if ( ! $adapter->is_active() ) {
				continue;
			}
			$this->active[ $id ] = $adapter;
			$adapter->register_hooks();
		}

		// Shared exclusion filters — every consumer (js-optimizer, rucss…)
		// runs its user list through these so adapters can append theirs.
		add_filter( 'blaminhor_essentials_cache_defer_js_exclusions', array( $this, 'merge_defer_js_exclusions' ), 10, 1 );
		add_filter( 'blaminhor_essentials_cache_delay_js_exclusions', array( $this, 'merge_delay_js_exclusions' ), 10, 1 );
		add_filter( 'blaminhor_essentials_cache_rucss_safelist', array( $this, 'merge_rucss_safelist' ), 10, 1 );
		add_filter( 'blaminhor_essentials_cache_async_css_excluded_handles', array( $this, 'merge_async_css_excluded_handles' ), 10, 1 );
	}

	/**
	 * @return array<string,bool>  Map of disabled adapter IDs.
	 */
	private function disabled_set() {
		$raw = $this->parent->get_setting( 'theme_compat_disabled', array() );
		if ( ! is_array( $raw ) ) {
			return array();
		}
		$out = array();
		foreach ( $raw as $id ) {
			$id = sanitize_key( (string) $id );
			if ( '' !== $id ) {
				$out[ $id ] = true;
			}
		}
		return $out;
	}

	/**
	 * @param string[] $list
	 * @return string[]
	 */
	public function merge_defer_js_exclusions( $list ) {
		if ( ! is_array( $list ) ) {
			$list = array();
		}
		foreach ( $this->active as $a ) {
			foreach ( $a->defer_js_exclusions() as $entry ) {
				$list[] = $entry;
			}
		}
		return array_values( array_unique( $list ) );
	}

	/**
	 * @param string[] $list
	 * @return string[]
	 */
	public function merge_delay_js_exclusions( $list ) {
		if ( ! is_array( $list ) ) {
			$list = array();
		}
		foreach ( $this->active as $a ) {
			foreach ( $a->delay_js_exclusions() as $entry ) {
				$list[] = $entry;
			}
		}
		return array_values( array_unique( $list ) );
	}

	/**
	 * @param string[] $list
	 * @return string[]
	 */
	public function merge_rucss_safelist( $list ) {
		if ( ! is_array( $list ) ) {
			$list = array();
		}
		foreach ( $this->active as $a ) {
			foreach ( $a->rucss_safelist() as $entry ) {
				$list[] = $entry;
			}
		}
		return array_values( array_unique( $list ) );
	}

	/**
	 * @param string[] $list
	 * @return string[]
	 */
	public function merge_async_css_excluded_handles( $list ) {
		if ( ! is_array( $list ) ) {
			$list = array();
		}
		foreach ( $this->active as $a ) {
			foreach ( $a->async_css_excluded_handles() as $entry ) {
				$list[] = $entry;
			}
		}
		return array_values( array_unique( $list ) );
	}

	/**
	 * @return array<int, array{id:string,label:string,active:bool,disabled:bool}>
	 */
	public function summary() {
		$disabled = $this->disabled_set();
		$out = array();
		foreach ( $this->registered as $id => $adapter ) {
			$out[] = array(
				'id'       => $id,
				'label'    => $adapter->label(),
				'active'   => $adapter->is_active(),
				'disabled' => isset( $disabled[ $id ] ),
			);
		}
		return $out;
	}
}
