<?php
/**
 * Sifency Animation Extension.
 *
 * Injects global animation controls and behavior into all Elementor widgets,
 * sections, columns, and containers.
 *
 * @package Sifency\Extension\Animation
 */

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

// Import namespaced animation dependencies
use Sifency\Traits\Sifency_Addons_Animation_Controls;
use Sifency\Traits\Sifency_Addons_Animation_Manager;

if ( ! class_exists( 'Sifency_Elementor_Animation_Controller' ) ) :

	final class Sifency_Elementor_Animation_Controller {

		use Sifency_Addons_Animation_Controls;

		private static $instance = null;

		private $registered_elements = array();

		/**
		 * Singleton instance
		 */
		public static function instance() {
			if ( null === self::$instance ) {
				self::$instance = new self();
			}
			return self::$instance;
		}

		/**
		 * Constructor – set up hooks
		 */
		private function __construct() {
			add_action( 'elementor/element/after_section_end', array( $this, 'global_register_controls' ), 999, 3 );

			add_action( 'elementor/element/common/section_advanced/after_section_end', array( $this, 'register_controls' ), 999, 2 );
			add_action( 'elementor/element/column/section_advanced/after_section_end', array( $this, 'register_controls' ), 999, 2 );
			add_action( 'elementor/element/section/section_advanced/after_section_end', array( $this, 'register_controls' ), 999, 2 );

			add_action( 'elementor/element/container/section_advanced/after_section_end', array( $this, 'register_controls' ), 999, 2 );

			// Apply data attributes before rendering on the frontend.
			add_action( 'elementor/frontend/section/before_render', array( $this, 'apply_render_attributes' ) );
			add_action( 'elementor/frontend/column/before_render', array( $this, 'apply_render_attributes' ) );
			add_action( 'elementor/frontend/container/before_render', array( $this, 'apply_render_attributes' ) );
			add_action( 'elementor/frontend/widget/before_render', array( $this, 'apply_render_attributes' ) );
		}

		/**
		 * Register Sifency Animation controls inside specific whitelisted sections globally.
		 */
		public function global_register_controls( $element, $section_id, $args ) {
			if ( ! $element instanceof \Elementor\Controls_Stack ) {
				return;
			}

			$target_sections = array(
				'section_effects',
				'section_advanced',
			);

			if ( in_array( $section_id, $target_sections, true ) ) {
				$key = spl_object_hash( $element );
				if ( isset( $this->registered_elements[ $key ] ) ) {
					return;
				}
				$this->add_Sifency_Addons_Animation_Controls( $element );
				$this->registered_elements[ $key ] = true;
			}
		}

		/**
		 * Register controls callback for explicit section hooks.
		 */
		public function register_controls( $element, $args ) {
			if ( ! $element instanceof \Elementor\Controls_Stack ) {
				return;
			}
			$key = spl_object_hash( $element );
			if ( isset( $this->registered_elements[ $key ] ) ) {
				return;
			}
			$this->add_Sifency_Addons_Animation_Controls( $element );
			$this->registered_elements[ $key ] = true;
		}

		/**
		 * Output animation data attributes on the element wrapper.
		 */
		public function apply_render_attributes( $element ) {
			$settings = $element->get_settings_for_display();

			if ( empty( $settings['sifency_animation_type'] ) ) {
				return;
			}

			$target = isset( $settings['sifency_animation_target'] ) ? $settings['sifency_animation_target'] : 'masterwrapper';

			$animation_manager = new Sifency_Addons_Animation_Manager( $settings );

			if ( $target === 'masterwrapper' || $target === 'wrapper' ) {
				// Both masterwrapper and wrapper apply to the Elementor outer _wrapper.
				// Sifency custom widgets that have an internal wrapper will override
				// this by calling get_wrapper_attributes() directly in their render().
				$attributes = $animation_manager->get_masterwrapper_attributes_array();
				if ( ! empty( $attributes ) ) {
					$element->add_render_attribute( '_wrapper', $attributes );
				}
			} elseif ( $target === 'child' ) {
				// Store a JSON stagger config on the _wrapper so the JS engine can
				// find direct children and animate them with stagger.
				$animation_attrs = $animation_manager->get_masterwrapper_attributes_array();
				if ( ! empty( $animation_attrs ) ) {
					// Pass animation data via a dedicated data attribute; JS picks this up.
					$element->add_render_attribute(
						'_wrapper',
						array(
							'data-sifency-stagger' => wp_json_encode( $animation_attrs ),
						)
					);
				}
			} elseif ( $target === 'custom' ) {
				// For custom class: store the selector + animation config on the wrapper.
				// JS will find children matching the selector and animate them.
				$classname = ! empty( $settings['sifency_animation_classname'] )
				? sanitize_text_field( $settings['sifency_animation_classname'] )
				: '';

				if ( ! empty( $classname ) ) {
					$animation_attrs = $animation_manager->get_custom_class_data_attrs();
					$element->add_render_attribute(
						'_wrapper',
						array(
							'data-sifency-animate-selector' => $classname,
							'data-sifency-animate-config' => wp_json_encode( $animation_attrs ),
						)
					);
				}
			}
			// Note: Sifency custom widgets (extending Sifency_Addons_Widget_Base) that
			// manually call get_wrapper_attributes() / get_item_attributes() in their own
			// render_dom() will produce the correct output regardless of what is set here.
		}
	}

	Sifency_Elementor_Animation_Controller::instance();

endif;
