<?php

namespace Brandy\BlockSettings\HoverAnimation;

use Brandy\Traits\SingletonTrait;

class Caller {
	use SingletonTrait;

	private $frontend_styles_enqueued = false;

	/**
	 * Blocks that can have hover animations applied to them.
	 */
	private $supported_blocks = array(
		'core/group',
		'core/image',
		'core/column',
		'core/cover',
		'core/heading',
		'core/paragraph',
		'woocommerce/product-image',
		'core/post-featured-image',
		'core/post-title',
		'woocommerce/product-button',
		'brandy/add-to-wishlist'
	);

	/**
	 * Blocks that can act as hover trigger parents.
	 * When hovered, child blocks with trigger=parent will animate.
	 */
	private $trigger_parent_blocks = array(
		'core/group',
		'core/column',
		'core/cover',
	);

	protected function __construct() {
		add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_settings_scripts' ) );
		add_action( 'enqueue_block_assets', array( $this, 'enqueue_editor_styles' ) );
		add_filter( 'render_block', array( $this, 'apply_hover_animation_to_blocks' ), 10, 3 );
	}

	private function is_supported_block( $block_name ) {
		return in_array( $block_name, $this->supported_blocks, true );
	}

	private function is_trigger_parent_block( $block_name ) {
		return in_array( $block_name, $this->trigger_parent_blocks, true );
	}

	public function enqueue_settings_scripts() {
		wp_enqueue_script(
			'brandy/hover-animation-controls',
			BRANDY_TEMPLATE_URL . '/inc/BlockSettings/HoverAnimation/script.js',
			array( 'wp-edit-post', 'wp-element', 'wp-compose', 'wp-blocks', 'wp-hooks', 'wp-i18n', 'wp-components', 'wp-block-editor' ),
			BRANDY_SCRIPT_VERSION,
			true
		);
	}

	public function enqueue_editor_styles() {
		$this->maybe_enqueue_frontend_styles( true );
	}

	public function maybe_enqueue_frontend_styles( $admin_enqueue = false ) {
		if ( ! $admin_enqueue && is_admin() ) {
			return;
		}
		if ( $admin_enqueue && ! is_admin() ) {
			return;
		}
		if ( $this->frontend_styles_enqueued ) {
			return;
		}
		$this->frontend_styles_enqueued = true;

		wp_enqueue_style(
			'brandy/hover-animation-style',
			BRANDY_TEMPLATE_URL . '/inc/BlockSettings/HoverAnimation/style.css',
			array(),
			BRANDY_SCRIPT_VERSION
		);
	}

	/**
	 * Text blocks where text-underline-slide wraps inner content in an inline span.
	 */
	private $text_blocks = array(
		'core/heading',
		'core/paragraph',
		'core/post-title',
	);

	public function apply_hover_animation_to_blocks( $html, $parsed_block, $block ) {
		if ( empty( $block->block_type ) || ! is_object( $block->block_type ) ) {
			return $html;
		}

		$block_name     = $block->block_type->name;
		$classes_to_add = array();
		$should_enqueue = false;
		$animation_type = '';

		// Use raw parsed attrs — custom attributes registered via JS filter
		// are not in $block->attributes (server strips unregistered attrs).
		$attrs = $parsed_block['attrs'] ?? array();

		// Check if this block is a hover trigger parent
		if ( $this->is_trigger_parent_block( $block_name ) ) {
			$is_trigger = $attrs['hoverAnimationTrigger'] ?? false;
			if ( $is_trigger ) {
				$classes_to_add[] = 'is-hover-trigger';
				$should_enqueue   = true;
			}
		}

		// Check if this block has a hover animation
		if ( $this->is_supported_block( $block_name ) ) {
			$hover_animation = $attrs['hoverAnimation'] ?? array();
			$animation_type  = $hover_animation['type'] ?? '';
			$animation_level = $hover_animation['level'] ?? '';
			$trigger         = $hover_animation['trigger'] ?? 'self';

			if ( ! empty( $animation_type ) && ! empty( $animation_level ) ) {
				$base_class = ( 'parent' === $trigger ) ? 'has-hover-child-animation' : 'has-hover-animation';

				$classes_to_add[] = $base_class;
				$classes_to_add[] = 'has-hover-' . esc_attr( $animation_type );
				$classes_to_add[] = 'has-hover-level-' . esc_attr( $animation_level );
				$should_enqueue   = true;
			}
		}

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

		$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 . ' ' . implode( ' ', $classes_to_add ) ) );

		// Add color CSS variable (underline or overlay) if set.
		$anim_color = $hover_animation['color'] ?? '';
		if ( ! empty( $anim_color ) ) {
			$css_var_name    = in_array( $animation_type, array( 'color-overlay', 'image-zoom-overlay' ), true ) ? '--brandy-overlay-color' : '--brandy-underline-color';
			$existing_style  = $tag->get_attribute( 'style' ) ?? '';
			if ( ! empty( $existing_style ) && ! str_ends_with( $existing_style, ';' ) ) {
				$existing_style .= ';';
			}
			$tag->set_attribute( 'style', $existing_style . $css_var_name . ':' . esc_attr( $anim_color ) );
		}

		$html = $tag->get_updated_html();

		// For text-underline-slide on text blocks, wrap inner content in inline span
		if ( 'text-underline-slide' === $animation_type && in_array( $block_name, $this->text_blocks, true ) ) {
			$html = $this->wrap_text_in_slide_span( $html );
		}

		if ( $should_enqueue ) {
			$this->maybe_enqueue_frontend_styles();
		}

		return $html;
	}

	/**
	 * Wrap inner HTML content of a block in an inline span for per-line underline slide.
	 * Matches the first tag's opening and closing, wraps everything between in a span.
	 */
	private function wrap_text_in_slide_span( $html ) {
		// Match: <tag ...>inner content</tag>
		if ( preg_match( '/^(\s*<(\w+)[^>]*>)(.*?)(<\/\2>\s*)$/s', $html, $matches ) ) {
			$open_tag  = $matches[1];
			$inner     = $matches[3];
			$close_tag = $matches[4];

			return $open_tag . '<span class="brandy-text-slide-inner">' . $inner . '</span>' . $close_tag;
		}

		return $html;
	}
}

Caller::get_instance();
