<?php

namespace orderflow\Facebook;

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

/**
 * Custom Events Manager
 * Handles Link, Scroll, Click, and Time-based custom events
 */
class Custom_Events_Manager {

	private static $_instance;
	private $link_events = array();
	private $scroll_events = array();
	private $click_events = array();
	private $time_events = array();

	public static function instance() {
		if ( is_null( self::$_instance ) ) {
			self::$_instance = new self();
		}
		return self::$_instance;
	}

	private function __construct() {
		$this->load_events();
		add_action( 'wp_footer', array( $this, 'output_custom_events_script' ), 20 );
	}

	/**
	 * Load custom events from options
	 */
	private function load_events() {
		$this->link_events = get_option( 'ads_fb_link_events', array() );
		$this->scroll_events = get_option( 'ads_fb_scroll_events', array() );
		$this->click_events = get_option( 'ads_fb_click_events', array() );
		$this->time_events = get_option( 'ads_fb_time_events', array() );
	}

	/**
	 * Check if any custom events are configured
	 */
	public function has_custom_events() {
		return ! empty( $this->link_events ) 
			|| ! empty( $this->scroll_events ) 
			|| ! empty( $this->click_events ) 
			|| ! empty( $this->time_events );
	}

	/**
	 * Output JavaScript code for custom events
	 */
	public function output_custom_events_script() {
		// Only output if Facebook pixel is configured
		if ( ! Facebook()->configured() ) {
			return;
		}

		// Only output if there are custom events
		if ( ! $this->has_custom_events() ) {
			return;
		}

		// Get standard params for custom events
		$standard_params = getStandardParams();

		?>
		<script type="text/javascript">
		(function($) {
			'use strict';
			
			// Configuration
			const CONFIG = {
				linkEvents: <?php echo wp_json_encode( $this->link_events ); ?>,
				scrollEvents: <?php echo wp_json_encode( $this->scroll_events ); ?>,
				clickEvents: <?php echo wp_json_encode( $this->click_events ); ?>,
				timeEvents: <?php echo wp_json_encode( $this->time_events ); ?>,
				standardParams: <?php echo wp_json_encode( $standard_params ); ?>
			};

			// State management
			const State = {
				isSetup: false,
				setupSelectors: {},
				pixel: null,
				clickTimestamps: {} // Track click timestamps to prevent duplicate in same click
			};

			/**
			 * Get Facebook Pixel instance
			 */
			function getPixel() {
				if (State.pixel) {
					return State.pixel;
				}

				if (typeof window.pys !== 'undefined' && window.pys.Facebook && typeof window.pys.Facebook.fireEvent === 'function') {
					State.pixel = window.pys.Facebook;
				} else if (typeof getPixelBySlag === 'function') {
					State.pixel = getPixelBySlag('orderflow_facebook');
				}

				return State.pixel;
			}

			/**
			 * Fire custom event to Facebook Pixel
			 * Each click will generate new event ID and fire to both server and browser
			 * Prevents duplicate events in the same click event
			 */
			function fireCustomEvent(eventName, clickTimestamp) {
				var pixel = getPixel();
				if (!pixel || typeof pixel.fireEvent !== 'function') {
					return;
				}

				// Prevent duplicate in same click event (within 100ms)
				if (clickTimestamp) {
					var eventKey = eventName + '_' + clickTimestamp;
					if (State.clickTimestamps[eventKey]) {
						return;
					}
					State.clickTimestamps[eventKey] = true;
					
					// Clean up after 1 second to prevent memory leak
					setTimeout(function() {
						delete State.clickTimestamps[eventKey];
					}, 1000);
				}

				// Prepare event parameters
				var eventParams = {};
				if (typeof CONFIG.standardParams !== 'undefined' && CONFIG.standardParams !== null) {
					for (var key in CONFIG.standardParams) {
						if (CONFIG.standardParams.hasOwnProperty(key)) {
							eventParams[key] = CONFIG.standardParams[key];
						}
					}
				}

				// Fire event with proper structure
				// This will send to both server-side and browser-side with same event ID
				// Each call will generate a new event ID automatically
				pixel.fireEvent(eventName, {
					name: eventName,
					params: eventParams,
					type: 'dynamic',
					eventID: [],
					e_id: 'custom_event_' + eventName.replace(/\s+/g, '_').toLowerCase()
				});
			}

			/**
			 * Setup Link Events (click handlers)
			 * Each click will fire a new event with new event ID
			 */
			function setupLinkEvents() {
				CONFIG.linkEvents.forEach(function(event) {
					if (!event.selector || !event.event_name) {
						return;
					}

					// Skip if selector already set up
					if (State.setupSelectors[event.selector]) {
			return;
		}

					State.setupSelectors[event.selector] = true;

					// Remove any existing listeners
					$(event.selector).off('click.customEventLink');

					// Attach click handler (fires on every click with new event ID)
					$(event.selector).on('click.customEventLink', function(e) {
						// Generate unique timestamp for this click
						var clickTimestamp = Date.now() + '_' + Math.random();
						fireCustomEvent(event.event_name, clickTimestamp);
					});
				});
			}

			/**
			 * Setup Click Events (click handlers)
			 * Each click will fire a new event with new event ID
			 */
			function setupClickEvents() {
				CONFIG.clickEvents.forEach(function(event) {
					if (!event.selector || !event.event_name) {
						return;
					}

					// Skip if selector already set up
					if (State.setupSelectors[event.selector]) {
						return;
					}

					State.setupSelectors[event.selector] = true;

					// Remove any existing listeners
					$(event.selector).off('click.customEventClick');

					// Attach click handler (fires on every click with new event ID)
					$(event.selector).on('click.customEventClick', function(e) {
						// Generate unique timestamp for this click
						var clickTimestamp = Date.now() + '_' + Math.random();
						fireCustomEvent(event.event_name, clickTimestamp);
					});
				});
			}

			/**
			 * Setup Scroll Events using IntersectionObserver
			 */
			function setupScrollEvents() {
				if (CONFIG.scrollEvents.length === 0) {
			return;
		}

				var observer = new IntersectionObserver(function(entries) {
					entries.forEach(function(entry) {
						if (entry.isIntersecting && entry.intersectionRatio >= 0.5) {
							var $el = $(entry.target);
							var eventName = $el.data('ads-scroll-event-fb');

							if (eventName && !$el.data('ads-scroll-sent')) {
								fireCustomEvent(eventName);
								$el.data('ads-scroll-sent', true);
							}
						}
					});
				}, { threshold: [0.5] });

				CONFIG.scrollEvents.forEach(function(event) {
					if (!event.selector || !event.event_name) {
						return;
					}

					$(event.selector).each(function() {
						var $el = $(this);
						$el.attr('data-ads-scroll-event-fb', event.event_name);
						observer.observe(this);
					});
				});
			}

			/**
			 * Setup Time Events (time-based triggers)
			 * Fires once when time threshold is reached
			 */
			function setupTimeEvents() {
				CONFIG.timeEvents.forEach(function(event) {
					if (!event.selector || !event.event_name || !event.seconds) {
						return;
					}

					var $target = $(event.selector);
					if ($target.length === 0) {
						return;
					}

					// Check if element is in viewport before starting timer
					var timer = setTimeout(function() {
						var $el = $(event.selector);
						if ($el.length > 0) {
							// Time events fire once, no timestamp needed
							fireCustomEvent(event.event_name);
						}
					}, event.seconds * 1000);

					// Store timer reference for potential cleanup
					$target.data('ads-time-timer', timer);
				});
			}

			/**
			 * Initialize all custom events
			 */
			function setupCustomEvents() {
				// Prevent duplicate setup
				if (State.isSetup) {
			return;
		}

				State.isSetup = true;

				// Setup all event types
				setupLinkEvents();
				setupClickEvents();
				setupScrollEvents();
				setupTimeEvents();
			}

			/**
			 * Wait for pixel to be initialized, then setup events
			 */
			function initCustomEvents() {
				var checkPixel = setInterval(function() {
					if (getPixel() && typeof getPixel().fireEvent === 'function') {
						clearInterval(checkPixel);
						setupCustomEvents();
					}
				}, 100);

				// Timeout after 5 seconds
				setTimeout(function() {
					clearInterval(checkPixel);
					if (getPixel()) {
						setupCustomEvents();
					}
				}, 5000);
			}

			// Initialize when document is ready
			$(document).ready(function() {
				initCustomEvents();
			});

		})(jQuery);
		</script>
		<?php
	}
}


