<?php
/**
 * PufferGo Admin Notice Guard
 *
 * Centralized suppression for third-party admin notices on PufferGo-owned screens.
 */

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

class PufferGo_Admin_Notice_Guard {

	/**
	 * Whether the current admin request is on a PufferGo-owned screen.
	 *
	 * @var bool
	 */
	private $is_active = false;

	/**
	 * Initialize hooks.
	 */
	public static function init() {
		$instance = new self();
		add_action( 'current_screen', array( $instance, 'bootstrap_for_screen' ), 1 );
		// Second pass: catch notices registered lazily inside admin_head (e.g. Kadence Pro).
		add_action( 'admin_head', array( $instance, 'second_pass_filter' ), 99 );
		add_action( 'admin_head', array( $instance, 'print_suppression_styles' ), 100 );
	}

	/**
	 * Activate the guard for PufferGo screens and suppress hook-based notices early.
	 *
	 * @param WP_Screen $screen Current screen.
	 * @return void
	 */
	public function bootstrap_for_screen( $screen ) {
		if ( ! $this->is_puffergo_screen( $screen ) ) {
			return;
		}

		$this->is_active = true;

		add_filter( 'admin_body_class', array( $this, 'add_body_class' ) );

		// Remove third-party notices at the source on PufferGo-owned screens,
		// while preserving PufferGo-owned callbacks.
		$this->filter_notice_hook( 'admin_notices' );
		$this->filter_notice_hook( 'all_admin_notices' );
		$this->filter_notice_hook( 'network_admin_notices' );
		$this->filter_notice_hook( 'user_admin_notices' );
	}

	/**
	 * Whether current screen belongs to PufferGo admin.
	 *
	 * @param WP_Screen|null $screen Screen object.
	 * @return bool
	 */
	private function is_puffergo_screen( $screen ) {
		if ( ! $screen || empty( $screen->id ) ) {
			return false;
		}

		return strpos( $screen->id, 'puffergo' ) !== false;
	}

	/**
	 * Add a stable body class for all PufferGo screens.
	 *
	 * @param string $classes Existing admin body classes.
	 * @return string
	 */
	public function add_body_class( $classes ) {
		if ( ! $this->is_active ) {
			return $classes;
		}

		return trim( $classes . ' puffergo-admin-screen' );
	}

	/**
	 * Remove non-PufferGo callbacks from an admin notice hook.
	 *
	 * @param string $hook_name Hook name.
	 * @return void
	 */
	private function filter_notice_hook( $hook_name ) {
		global $wp_filter;

		if ( empty( $wp_filter[ $hook_name ] ) || ! $wp_filter[ $hook_name ] instanceof WP_Hook ) {
			return;
		}

		foreach ( $wp_filter[ $hook_name ]->callbacks as $priority => $callbacks ) {
			foreach ( $callbacks as $callback_id => $registered_callback ) {
				if ( empty( $registered_callback['function'] ) || ! $this->is_allowed_notice_callback( $registered_callback['function'] ) ) {
					unset( $wp_filter[ $hook_name ]->callbacks[ $priority ][ $callback_id ] );
				}
			}

			if ( empty( $wp_filter[ $hook_name ]->callbacks[ $priority ] ) ) {
				unset( $wp_filter[ $hook_name ]->callbacks[ $priority ] );
			}
		}
	}

	/**
	 * Decide whether a notice callback should be preserved.
	 *
	 * @param callable|string|array $callback Registered callback.
	 * @return bool
	 */
	private function is_allowed_notice_callback( $callback ) {
		$callback_name = '';

		if ( is_string( $callback ) ) {
			$callback_name = $callback;
		} elseif ( is_array( $callback ) && isset( $callback[0], $callback[1] ) ) {
			$owner         = is_object( $callback[0] ) ? get_class( $callback[0] ) : (string) $callback[0];
			$callback_name = $owner . '::' . $callback[1];
		}

		if ( ! $callback_name ) {
			return false;
		}

		return 0 === strpos( $callback_name, 'PufferGo_' ) || 0 === strpos( $callback_name, 'puffergo_' );
	}

	/**
	 * Second-pass filter: some plugins (e.g. Kadence Theme Pro) register their
	 * admin_notices callbacks inside admin_head, after our initial sweep on current_screen.
	 * Running again at admin_head priority 99 catches those late registrations.
	 */
	public function second_pass_filter() {
		if ( ! $this->is_active ) {
			return;
		}

		$this->filter_notice_hook( 'admin_notices' );
		$this->filter_notice_hook( 'all_admin_notices' );
		$this->filter_notice_hook( 'network_admin_notices' );
		$this->filter_notice_hook( 'user_admin_notices' );
	}

	/**
	 * Print static CSS suppression for notices already rendered before app mount.
	 */
	public function print_suppression_styles() {
		if ( ! $this->is_active ) {
			return;
		}
		?>
		<style id="puffergo-admin-notice-guard">
			body.puffergo-admin-screen #wpbody-content > .notice:not(.puffergo-admin-notice),
			body.puffergo-admin-screen #wpbody-content > .error:not(.puffergo-admin-notice),
			body.puffergo-admin-screen #wpbody-content > .updated:not(.puffergo-admin-notice),
			body.puffergo-admin-screen #wpbody-content > .update-nag:not(.puffergo-admin-notice),
			body.puffergo-admin-screen #wpbody-content .wrap > .notice:not(.puffergo-admin-notice),
			body.puffergo-admin-screen #wpbody-content .wrap > .error:not(.puffergo-admin-notice),
			body.puffergo-admin-screen #wpbody-content .wrap > .updated:not(.puffergo-admin-notice),
			body.puffergo-admin-screen #wpbody-content .wrap > .update-nag:not(.puffergo-admin-notice) {
				display: none !important;
			}
		</style>
		<?php
	}
}
