<?php
/**
 * Script optimizer.
 *
 * Adds defer attribute to enqueued scripts and optionally removes
 * jQuery Migrate to reduce render-blocking resources.
 *
 * @package MonitorCat\Modules\Speed\Optimizer
 */

declare(strict_types=1);

namespace MonitorCat\Modules\Speed\Optimizer;

defined( 'ABSPATH' ) || exit;

use MonitorCat\Settings;

/**
 * Optimizes script loading by deferring and removing unnecessary scripts.
 */
final class ScriptOptimizer {

	/**
	 * Plugin settings.
	 *
	 * @var Settings
	 */
	private Settings $settings;

	/**
	 * Script handles that must NOT be deferred (core dependencies).
	 *
	 * @var string[]
	 */
	private const EXCLUDED_HANDLES = array(
		'jquery-core',
		'jquery',
		'wp-polyfill',
		'wp-hooks',
	);

	/**
	 * Constructor.
	 *
	 * @param Settings $settings Plugin settings.
	 */
	public function __construct( Settings $settings ) {
		$this->settings = $settings;
	}

	/**
	 * Register hooks if the optimization is enabled.
	 */
	public function boot(): void {
		if ( ! $this->settings->get( 'speed.optimize_scripts', true ) ) {
			return;
		}

		// Only on frontend — never touch admin scripts.
		if ( is_admin() ) {
			return;
		}

		// Add defer to scripts.
		add_filter( 'script_loader_tag', array( $this, 'add_defer_attribute' ), 10, 3 );

		// Remove jQuery Migrate.
		if ( $this->settings->get( 'speed.remove_jquery_migrate', true ) ) {
			add_action( 'wp_default_scripts', array( $this, 'remove_jquery_migrate' ) );
		}
	}

	/**
	 * Add defer attribute to script tags that don't already have async or defer.
	 *
	 * @param string $tag    The full script tag HTML.
	 * @param string $handle The script handle.
	 * @param string $src    The script source URL.
	 * @return string Modified script tag.
	 */
	public function add_defer_attribute( string $tag, string $handle, string $src ): string {
		// Skip excluded handles.
		if ( in_array( $handle, self::EXCLUDED_HANDLES, true ) ) {
			return $tag;
		}

		// Skip if already has async or defer.
		if ( preg_match( '/\b(async|defer)\b/', $tag ) ) {
			return $tag;
		}

		// Skip inline scripts (no src).
		if ( empty( $src ) ) {
			return $tag;
		}

		return str_replace( ' src=', ' defer src=', $tag );
	}

	/**
	 * Remove jQuery Migrate from the default scripts.
	 *
	 * @param \WP_Scripts $scripts The WP_Scripts instance.
	 */
	public function remove_jquery_migrate( \WP_Scripts $scripts ): void {
		if ( ! isset( $scripts->registered['jquery'] ) ) {
			return;
		}

		$jquery = $scripts->registered['jquery'];

		$jquery->deps = array_diff( $jquery->deps, array( 'jquery-migrate' ) );
	}
}
