<?php

namespace Brandy\BlockSettings\ResponsiveTypography;

use Brandy\Traits\SingletonTrait;
use Brandy\Interfaces\ExternalBlockSettingsInterface;

class Caller implements ExternalBlockSettingsInterface {
	use SingletonTrait;

	protected $supported_blocks = array(
		'core/paragraph',
		'core/heading',
		'core/list',
	);

	/**
	 * Map of responsive typography keys to CSS property names.
	 */
	private static $css_property_map = array(
		'fontSize'       => 'font-size',
		'lineHeight'     => 'line-height',
		'fontWeight'     => 'font-weight',
		'letterSpacing'  => 'letter-spacing',
		'textTransform'  => 'text-transform',
		'textDecoration' => 'text-decoration',
		'fontStyle'      => 'font-style',
	);

	protected function __construct() {
		add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_settings_scripts' ) );

		foreach ( $this->supported_blocks as $block ) {
			add_filter( 'render_block_' . $block, array( $this, 'apply_responsive_typography' ), 100, 3 );
		}
	}

	/**
	 * Satisfy ExternalBlockSettingsInterface — no separate attribute needed,
	 * data lives in style.responsiveTypography.
	 */
	public function declare_attribute( $settings ) {
		return $settings;
	}

	public function is_supported_block( $block ) {
		if ( empty( $block['name'] ) ) {
			return false;
		}
		return in_array( $block['name'], $this->supported_blocks );
	}

	public function enqueue_settings_scripts() {
		wp_enqueue_script(
			'brandy/responsive-typography',
			BRANDY_TEMPLATE_URL . '/inc/BlockSettings/ResponsiveTypography/script.js',
			array( 'wp-edit-post' ),
			BRANDY_SCRIPT_VERSION,
			true
		);
	}

	/**
	 * Resolve font size value — presets become CSS custom properties.
	 */
	private function resolve_font_size_value( $value, $type ) {
		if ( 'preset' === $type && ! empty( $value ) ) {
			return 'var(--wp--preset--font-size--' . sanitize_title( $value ) . ')';
		}
		return $value;
	}

	/**
	 * Sanitize a CSS value — strip characters that could break out of a declaration.
	 */
	private function sanitize_css_value( $value ) {
		// Allow var(--custom-property) for preset font sizes
		if ( preg_match( '/^var\(--[a-zA-Z0-9-]+\)$/', $value ) ) {
			return $value;
		}
		return preg_replace( '/[^a-zA-Z0-9_.% -]/', '', $value );
	}

	/**
	 * Build CSS declarations string for a device's typography overrides.
	 */
	private function build_device_css( $device_data, $class_name ) {
		if ( empty( $device_data ) || ! is_array( $device_data ) ) {
			return '';
		}

		$declarations = array();

		foreach ( self::$css_property_map as $key => $css_prop ) {
			if ( ! isset( $device_data[ $key ] ) || '' === $device_data[ $key ] ) {
				continue;
			}

			$value = $device_data[ $key ];

			if ( 'fontSize' === $key ) {
				$type  = $device_data['fontSizeType'] ?? 'custom';
				$value = $this->resolve_font_size_value( $value, $type );
			}

			$declarations[] = $css_prop . ':' . $this->sanitize_css_value( $value ) . '!important';
		}

		if ( empty( $declarations ) ) {
			return '';
		}

		return '.' . $class_name . '{' . implode( ';', $declarations ) . '}';
	}

	/**
	 * Apply responsive typography styles on frontend.
	 */
	public function apply_responsive_typography( $html, $_, $block ) {
		$style            = $block->attributes['style'] ?? array();
		$responsive_typo  = $style['responsiveTypography'] ?? array();

		if ( empty( $responsive_typo ) ) {
			return $html;
		}

		$tablet_data = $responsive_typo['tablet'] ?? array();
		$mobile_data = $responsive_typo['mobile'] ?? array();

		if ( empty( $tablet_data ) && empty( $mobile_data ) ) {
			return $html;
		}

		// Mobile inherits tablet values for properties not explicitly set
		if ( ! empty( $tablet_data ) && ! empty( $mobile_data ) ) {
			$mobile_data = array_merge( $tablet_data, $mobile_data );
		} elseif ( ! empty( $tablet_data ) && empty( $mobile_data ) ) {
			$mobile_data = $tablet_data;
		}

		$class_name = 'brandy-rt-' . wp_unique_id();

		$tag = new \WP_HTML_Tag_Processor( $html );
		if ( ! $tag->next_tag() ) {
			return $html;
		}

		$existing_class = $tag->get_attribute( 'class' );
		$tag->set_attribute( 'class', trim( ( $existing_class ?? '' ) . ' ' . $class_name ) );
		$html = $tag->get_updated_html();

		$css_parts = array();

		$tablet_css = $this->build_device_css( $tablet_data, $class_name );
		if ( ! empty( $tablet_css ) ) {
			$css_parts[] = '@media screen and (min-width:' . ( BRANDY_MOBILE_MAX_WIDTH + 1 ) . 'px) and (max-width:' . BRANDY_TABLET_MAX_WIDTH . 'px){' . $tablet_css . '}';
		}

		$mobile_css = $this->build_device_css( $mobile_data, $class_name );
		if ( ! empty( $mobile_css ) ) {
			$css_parts[] = '@media screen and (max-width:' . BRANDY_MOBILE_MAX_WIDTH . 'px){' . $mobile_css . '}';
		}

		if ( empty( $css_parts ) ) {
			return $html;
		}

		return $html . '<style>' . implode( '', $css_parts ) . '</style>';
	}
}

Caller::get_instance();
