<?php
/**
 * UAGB Post.
 *
 * @package UAGB
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

if ( ! class_exists( 'UAGB_Image' ) ) {

	/**
	 * Class UAGB_Image.
	 */
	class UAGB_Image {


		/**
		 * Member Variable
		 *
		 * @since 2.0.0
		 * @var instance
		 */
		private static $instance;


		/**
		 *  Initiator
		 *
		 * @since 2.0.0
		 */
		public static function get_instance() {
			if ( ! isset( self::$instance ) ) {
				self::$instance = new self();
			}
			return self::$instance;
		}

		/**
		 * Constructor
		 */
		public function __construct() {
			add_action( 'init', array( $this, 'register_blocks' ) );
			add_filter( 'render_block_uagb/image', array( $this, 'sanitize_block_output' ) );
		}

		/**
		 * Register the Image block on server.
		 *
		 * @since 2.0.0
		 */
		public function register_blocks() {
			// Check if the register function exists.
			if ( ! function_exists( 'register_block_type' ) ) {
				return;
			}

			register_block_type(
				'uagb/image',
				array(
					'supports' => array(
						'color' => array(
							'__experimentalDuotone' => 'img',
							'text'                  => false,
							'background'            => false,
						),
					),
				)
			);
		}

		/**
		 * Sanitize the rendered block output to strip any injected event handlers.
		 *
		 * Runs the rendered HTML through KSES with the 'post' context allowlist so
		 * malicious attributes (onload, onfocus, etc.) injected via crafted block
		 * markup in the Code Editor cannot reach the frontend, regardless of how
		 * they survived post-save filtering.
		 *
		 * In the Customizer preview, UAGB_Rest_API::content_pre_render() appends the
		 * block's generated CSS as an inline <style> tag (plus Google Fonts <link>
		 * tags) to the block's innerContent so styles travel with the block HTML
		 * during preview and selective refresh. Since wp_kses_post() strips those
		 * tags but leaves the raw CSS text behind, the allowlist is extended with
		 * <style> and <link> only when is_customize_preview() is true. These tags
		 * cannot execute script, and the link tag is restricted to what the plugin
		 * emits: rel="stylesheet" with a Google Fonts href. The frontend allowlist
		 * remains unchanged.
		 *
		 * @since x.x.x
		 * @param string $block_content Rendered block HTML.
		 * @return string Sanitized HTML.
		 */
		public function sanitize_block_output( $block_content ) {
			$allowed_tags = wp_kses_allowed_html( 'post' );

			/*
			 * is_customize_preview() is deliberately narrower than the $wp_customize
			 * global that gates the injection in content_pre_render(): it is only true
			 * while the preview itself renders, which is the exact context that needs
			 * the allowance. Do not replace it with a $wp_customize check.
			 *
			 * KSES does not parse CSS, so the <style> tag's text content passes through
			 * unfiltered. That is acceptable only because rendering a Customizer preview
			 * requires the customize capability or a changeset preview link generated by
			 * such a user — do not widen this condition beyond the Customizer preview.
			 */
			if ( is_customize_preview() ) {
				$allowed_tags['style'] = array(
					'class' => true,
				);
				$allowed_tags['link']  = array(
					'rel'   => array(
						'values' => array( 'stylesheet' ),
					),
					'href'  => array(
						'value_callback' => array( __CLASS__, 'is_google_fonts_href' ),
					),
					'media' => true,
				);
			}

			return wp_kses( $block_content, $allowed_tags );
		}

		/**
		 * Verify that a Customizer-preview stylesheet link points to Google Fonts.
		 *
		 * Used as a KSES 'value_callback' so the only <link href> value that
		 * survives sanitize_block_output() is the Google Fonts URL emitted by
		 * UAGB_Rest_API::content_pre_render().
		 *
		 * @since x.x.x
		 * @param string $value The href attribute value.
		 * @return bool True when the URL host is fonts.googleapis.com.
		 */
		public static function is_google_fonts_href( $value ) {
			return 'fonts.googleapis.com' === wp_parse_url( $value, PHP_URL_HOST );
		}
	}

	/**
	 *  Prepare if class 'UAGB_Image' exist.
	 *  Kicking this off by calling 'get_instance()' method
	 */
	UAGB_Image::get_instance();
}
