<?php

namespace Brandy\BlockSettings\DisplayAnimation;

use Brandy\Traits\SingletonTrait;

class Caller {
	use SingletonTrait;

	public const DEFAULT_SETTINGS = array(
		'type'               => 'none',
		'duration'           => 1,
		'delay'              => 0,
		'scale'              => 1.3,
		'distanceFromOrigin' => 50,
		'animateOnce'        => false,
		'wordDelay'          => 0.2,
	);

	private const SLIDE_TEXT_TYPES = array( 'slide_text_up', 'slide_text_left', 'slide_text_right' );

	/**
	 * Track if frontend assets already enqueued.
	 *
	 * @var bool
	 */
	private $frontend_assets_enqueued = false;

	protected function __construct() {
		add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_settings_scripts' ) );
		add_filter( 'render_block', array( $this, 'add_animation_data_attribute' ), 10, 2 );
	}

	public function enqueue_settings_scripts() {
		wp_enqueue_script(
			'brandy/display-animation-controls',
			BRANDY_TEMPLATE_URL . '/inc/BlockSettings/DisplayAnimation/editor-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
		);
	}

	/**
	 * Enqueue frontend assets only when needed.
	 */
	private function maybe_enqueue_frontend_assets() {
		if ( $this->frontend_assets_enqueued ) {
			return;
		}
		$this->frontend_assets_enqueued = true;
		wp_register_style( 'brandy/display-animation-style', false );
		wp_enqueue_style( 'brandy/display-animation-style' );
		wp_add_inline_style( 'brandy/display-animation-style', $this->get_css() );
		wp_enqueue_script( 'brandy/display-animation-script', BRANDY_TEMPLATE_URL . '/inc/BlockSettings/DisplayAnimation/script.js', array( 'jquery' ), BRANDY_SCRIPT_VERSION, true );
	}

	public function get_css() {
		ob_start();
		?>
		@keyframes bbFadeInDown{0%{opacity:0;transform:translateY(calc(var(--animation-distance-from-origin)*-1));}100%{opacity:1;transform:translateY(0);}}@keyframes bbFadeInUp{0%{opacity:0;transform:translateY(var(--animation-distance-from-origin));}100%{opacity:1;transform:translateY(0);}}@keyframes bbFadeInLeft{0%{opacity:0;transform:translateX(calc(var(--animation-distance-from-origin)*-1));}100%{opacity:1;transform:translateX(0);}}@keyframes bbFadeInRight{0%{opacity:0;transform:translateX(var(--animation-distance-from-origin));}100%{opacity:1;transform:translateX(0);}}@keyframes bbSlideInLeft{from{opacity:0;transform:translateX(calc(var(--animation-distance-from-origin)*-1));}to{opacity:1;transform:translateX(0);}}@keyframes bbSlideInRight{from{opacity:0;transform:translateX(var(--animation-distance-from-origin));}to{opacity:1;transform:translateX(0);}}@keyframes bbSlideOutLeft{from{opacity:1;transform:translateX(0);}to{opacity:0;transform:translateX(calc(var(--animation-distance-from-origin)*-1));}}@keyframes bbSlideOutRight{from{opacity:1;transform:translateX(0);}to{opacity:0;transform:translateX(var(--animation-distance-from-origin));}}@keyframes bbZoomIn{0%{opacity:0;transform:scale(var(--animation-scale),var(--animation-scale));}100%{opacity:1;transform:scale(1,1);}}@keyframes bbZoomOut{0%{opacity:0;transform:scale(var(--animation-scale),var(--animation-scale));}100%{opacity:1;transform:scale(1,1);}}@keyframes bbBounce{0%,20%,50%,80%,100%{transform:translateY(0);}40%{transform:translateY(-30px);}60%{transform:translateY(-15px);}}@keyframes bbBounceIn{0%,20%,50%,80%,100%{transform:translateY(0);}0%,30%{opacity:0;}40%{transform:translateY(-30px);}60%{transform:translateY(-15px);}100%{opacity:1;}}.bb-animated{animation:none!important;}[class*="bb-animate--fade_in"]:not(.bb-animated),[class*="bb-animate--slide_in"]:not(.bb-animated),[class*="bb-animate--bounce_in"]:not(.bb-animated){opacity:0;}.bb-animate--fade_in_down{animation-name:bbFadeInDown;}.bb-animate--fade_in_up{animation-name:bbFadeInUp;}.bb-animate--fade_in_right{animation-name:bbFadeInRight;}.bb-animate--fade_in_left{animation-name:bbFadeInLeft;}.bb-animate--slide_in_left{animation-name:bbSlideInLeft;}.bb-animate--slide_in_right{animation-name:bbSlideInRight;}.bb-animate--slide_out_left{animation-name:bbSlideOutLeft;}.bb-animate--slide_out_right{animation-name:bbSlideOutRight;}.bb-animate--zoom_in{animation-name:bbZoomIn;}.bb-animate--zoom_out{animation-name:bbZoomOut;}.bb-animate--bounce{animation-name:bbBounce;}.bb-animate--bounce_in{animation-name:bbBounceIn;}@keyframes bbSlideTextUp{from{opacity:0;transform:translateY(0.5em);}to{opacity:1;transform:translateY(0);}}@keyframes bbSlideTextLeft{from{opacity:0;transform:translateX(-0.5em);}to{opacity:1;transform:translateX(0);}}@keyframes bbSlideTextRight{from{opacity:0;transform:translateX(0.5em);}to{opacity:1;transform:translateX(0);}}[class*="bb-animate--slide_text"]:not(.bb-animating) .bb-word{opacity:0;}.bb-animate--slide_text_up.bb-animating .bb-word{display:inline-block;animation-name:bbSlideTextUp;animation-fill-mode:forwards;}.bb-animate--slide_text_left.bb-animating .bb-word{display:inline-block;animation-name:bbSlideTextLeft;animation-fill-mode:forwards;}.bb-animate--slide_text_right.bb-animating .bb-word{display:inline-block;animation-name:bbSlideTextRight;animation-fill-mode:forwards;}.bb-animate--slide_text_up.bb-animated .bb-word,.bb-animate--slide_text_left.bb-animated .bb-word,.bb-animate--slide_text_right.bb-animated .bb-word{opacity:1!important;animation:none;}
		<?php
		return ob_get_clean();
	}

	public function add_animation_data_attribute( $content, $block ) {

		if ( empty( $block['attrs'] ) ) {
			return $content;
		}

		$attributes = (array) $block['attrs'];

		$escaped_data_attributes = array();
		$escaped_style           = '';
		$display_animation       = array();

		foreach ( $attributes as $key => $value ) {
			if ( 'style' !== $key || empty( $value['displayAnimation'] ) ) {
				continue;
			}
			$display_animation = $value['displayAnimation'];

			$escaped_data_attributes['class'] = 'bb-animate bb-animate--' . esc_attr( $display_animation['type'] );
			if ( $display_animation['animateOnce'] ?? false ) {
				$escaped_data_attributes['class'] .= ' bb-animate-once';
			}
			$escaped_style  = 'animation-duration:' . esc_attr( $display_animation['duration'] ?? self::DEFAULT_SETTINGS['duration'] ) . 's;';
			$escaped_style .= 'animation-delay:' . esc_attr( $display_animation['delay'] ?? self::DEFAULT_SETTINGS['delay'] ) . 's;';
			$escaped_style .= '--animation-distance-from-origin:' . esc_attr( $display_animation['distanceFromOrigin'] ?? self::DEFAULT_SETTINGS['distanceFromOrigin'] ) . 'px;';
			if ( in_array( $display_animation['type'], array( 'scale_down', 'scale_up' ) ) ) {
				$escaped_data_attributes['data-animation-scale'] = esc_attr( $display_animation['scale'] ?? self::DEFAULT_SETTINGS['scale'] );
				if ( 'scale_down' === $display_animation['type'] ) {
					$escaped_style .= '--animation-initial-scale:' . esc_attr( $display_animation['scale'] ?? self::DEFAULT_SETTINGS['scale'] ) . ';transform: scale(' . esc_attr( $display_animation['scale'] ?? self::DEFAULT_SETTINGS['scale'] ) . ');';
				} else {
					$escaped_style .= '--animation-initial-scale:1;transform: scale(1);';
				}
			}
			if ( in_array( $display_animation['type'], self::SLIDE_TEXT_TYPES, true ) ) {
				$escaped_data_attributes['data-word-delay'] = esc_attr( $display_animation['wordDelay'] ?? self::DEFAULT_SETTINGS['wordDelay'] );
			}
		}

		$tags = new \WP_HTML_Tag_Processor( $content );
		if ( $tags->next_tag() ) {
			if ( ! empty( $escaped_style ) ) {
				$existing_style = $tags->get_attribute( 'style' );
				$updated_style  = '';

				if ( empty( $existing_style ) ) {
					$existing_style = '';
				} elseif ( ! str_ends_with( $existing_style, ';' ) ) {
					$existing_style .= ';';
				}
				$updated_style  = $existing_style;
				$updated_style .= $escaped_style;
				$tags->set_attribute( 'style', $updated_style );
			}
			if ( ! empty( $escaped_data_attributes ) ) {
				foreach ( $escaped_data_attributes as $data_attribute_key => $data_attribute_value ) {
					if ( 'class' === $data_attribute_key ) {
						$data_attribute_value = ( $tags->get_attribute( 'class' ) ?? '' ) . ' ' . $data_attribute_value;
					}
					$tags->set_attribute( $data_attribute_key, $data_attribute_value );
				}
				$this->maybe_enqueue_frontend_assets();
			}
			$content = $tags->get_updated_html();
		}

		if ( ! empty( $display_animation ) && in_array( $display_animation['type'], self::SLIDE_TEXT_TYPES, true ) ) {
			$word_delay = (float) ( $display_animation['wordDelay'] ?? self::DEFAULT_SETTINGS['wordDelay'] );
			$duration   = (float) ( $display_animation['duration'] ?? self::DEFAULT_SETTINGS['duration'] );
			$content    = self::wrap_words_in_html( $content, $word_delay, $duration );
		}

		return preg_replace( '/^<div /', '<div ' . implode( ' ', $escaped_data_attributes ) . ' ', trim( $content ) );
	}

	/**
	 * Wrap each word in text nodes with <span class="bb-word"> and staggered animation delays.
	 * Preserves inner HTML structure (links, strong, em, etc.).
	 */
	private static function wrap_words_in_html( $html, $word_delay, $duration ) {
		$word_index = 0;

		$result = preg_replace_callback(
			'/(<[^>]+>)|([^<]+)/',
			function ( $matches ) use ( $word_delay, $duration, &$word_index ) {
				// HTML tag — pass through unchanged.
				if ( ! empty( $matches[1] ) ) {
					return $matches[1];
				}

				// Text node — split into words and wrap each.
				$text   = $matches[2];
				$output = '';
				// Split on whitespace and &nbsp; / &#160; entities.
				$tokens = preg_split( '/(\s+|&nbsp;|&#160;)/', $text, -1, PREG_SPLIT_DELIM_CAPTURE );

				foreach ( $tokens as $token ) {
					if ( '' === $token ) {
						continue;
					}
					// Whitespace or &nbsp; — keep as separator.
					if ( ctype_space( $token ) || '&nbsp;' === $token || '&#160;' === $token ) {
						$output .= ' ';
						continue;
					}
					$delay   = round( $word_index * $word_delay, 3 );
					$output .= '<span class="bb-word" style="opacity:0;animation-delay:' . $delay . 's;animation-duration:' . $duration . 's">' . $token . '</span>';
					++$word_index;
				}

				return $output;
			},
			$html
		);

		return $result;
	}
}

Caller::get_instance();
