<?php
/**
 * Third-party compatibility shims.
 *
 * Keeps the gift-wrapping UI working when aggressive optimisation plugins are
 * active. Right now this covers WP Rocket: its "Delay JavaScript execution",
 * JS minify/combine and "Remove Unused CSS" features can otherwise break the
 * cart button (dead clicks) or strip its styling.
 *
 * @package CartGiftWrapping
 */

defined( 'ABSPATH' ) || exit;

/**
 * Class CGWFW_Compat
 *
 * Registers filters for known optimisation plugins. All hooks are no-ops unless
 * the relevant plugin (e.g. WP Rocket) is active and applies them.
 */
final class CGWFW_Compat {

	/**
	 * Constructor: wire up the compatibility filters.
	 */
	public function __construct() {
		// WP Rocket: keep our scripts out of delay/combine/minify so the cart
		// button stays interactive, and protect our CSS from Remove Unused CSS.
		add_filter( 'rocket_delay_js_exclusions', array( $this, 'rocket_exclude_from_delay' ) );
		add_filter( 'rocket_exclude_js', array( $this, 'rocket_exclude_from_minify' ) );
		add_filter( 'rocket_minify_excluded_external_js', array( $this, 'rocket_exclude_external' ) );
		add_filter( 'rocket_rucss_safelist', array( $this, 'rocket_css_safelist' ) );
	}

	/**
	 * Our front-end script paths, relative to the site root, derived from the
	 * plugin URL so a renamed plugin folder still resolves correctly.
	 *
	 * @return string[] Relative URL paths, e.g. /wp-content/plugins/.../cgwfw.js.
	 */
	private function script_paths() {
		$base = (string) wp_parse_url( CGWFW_URL, PHP_URL_PATH );
		$base = rtrim( $base, '/' );

		return array(
			$base . '/assets/js/cgwfw.js',
			$base . '/assets/js/cgwfw-blocks.js',
		);
	}

	/**
	 * Exclude our scripts from WP Rocket's "Delay JavaScript execution".
	 *
	 * This is the most common cause of a dead gift-wrap button, since our click
	 * handlers and jQuery would otherwise be held back until user interaction.
	 *
	 * @param array $excluded Existing exclusion patterns.
	 * @return array
	 */
	public function rocket_exclude_from_delay( $excluded ) {
		$excluded = is_array( $excluded ) ? $excluded : array();
		return array_merge( $excluded, $this->script_paths() );
	}

	/**
	 * Exclude our scripts from WP Rocket's JS minify/combine.
	 *
	 * @param array $excluded Existing excluded JS paths.
	 * @return array
	 */
	public function rocket_exclude_from_minify( $excluded ) {
		$excluded = is_array( $excluded ) ? $excluded : array();
		return array_merge( $excluded, $this->script_paths() );
	}

	/**
	 * Belt-and-braces: also list the file names for external-JS exclusion, which
	 * some WP Rocket versions consult when deciding what to combine.
	 *
	 * @param array $excluded Existing excluded external JS identifiers.
	 * @return array
	 */
	public function rocket_exclude_external( $excluded ) {
		$excluded = is_array( $excluded ) ? $excluded : array();
		return array_merge( $excluded, array( 'cgwfw.js', 'cgwfw-blocks.js' ) );
	}

	/**
	 * Keep our selectors when WP Rocket removes unused CSS, so the button
	 * styling (including states only present after interaction) survives.
	 *
	 * @param array $safelist Existing safelisted selectors.
	 * @return array
	 */
	public function rocket_css_safelist( $safelist ) {
		$safelist = is_array( $safelist ) ? $safelist : array();
		return array_merge( $safelist, array( 'cgwfw' ) );
	}
}
