<?php
/**
 * File to tracking functionality.
 */

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

/**
 * Class to handle visitors tracking.
 */
class SimpleStats_Tracking {

	/**
	 * Hold the instance.
	 *
	 * @var self
	 */
	private static $instance;

	/**
	 * Get instance of class.
	 *
	 * @return self
	 */
	public static function get_instance() {
		if ( ! self::$instance ) {
			self::$instance = new self();
		}

		return self::$instance;
	}

	/**
	 * Script handle for the SimpleStats tracking pixel.
	 */
	const PIXEL_HANDLE = 'simplestats-pixel';

	/**
	 * Constructor function of the class.
	 */
	private function __construct() {
		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_pixel' ) );
		add_filter( 'script_loader_tag', array( $this, 'defer_pixel' ), 10, 2 );

		$this->load_providers();
	}

	/**
	 * Enqueue the SimpleStats tracking pixel in the site head.
	 *
	 * Enqueued (rather than echoed in wp_head) per the WordPress.org guideline
	 * to use the script API for all JS output. The defer attribute is added by
	 * defer_pixel() on the script_loader_tag filter — wp_enqueue_script()'s
	 * native `strategy` argument is WP 6.3+, but this plugin supports 5.6.
	 */
	public function enqueue_pixel() {
		$connection = simplestats_get_connection();

		if ( empty( $connection ) || empty( $connection['pixel_key'] ) ) {
			return;
		}

		$settings = simplestats_get_settings();

		if ( ! empty( $settings['exclude_admins'] ) && current_user_can( 'manage_options' ) ) {
			return;
		}

		$src = simplestats_get_app_url() . '/pixel/' . rawurlencode( $connection['pixel_key'] );

		/*
		 * $ver is deliberately null.
		 *
		 * This script is served by the SimpleStats app, not shipped inside the
		 * plugin, so there is no bundled file whose browser cache needs busting
		 * on plugin update. Passing SIMPLESTATS_PLUGIN_VERSION would append a
		 * `?ver=` query string to a third-party URL and invalidate the vendor's
		 * CDN cache on every plugin release, for a file whose freshness the
		 * vendor already controls through its own cache headers. Passing `false`
		 * would be worse still — that appends the WordPress core version.
		 *
		 * $in_footer is explicitly false so the pixel stays in <head>, where it
		 * can record a visit before the reader navigates away; defer_pixel()
		 * keeps it from blocking render.
		 */
		// phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion -- Externally hosted script, versioned by the vendor; see above.
		wp_enqueue_script( self::PIXEL_HANDLE, $src, array(), null, false );
	}

	/**
	 * Add the `defer` attribute to the tracking pixel's <script> tag.
	 *
	 * @param string $tag    The full <script> tag for the enqueued script.
	 * @param string $handle The script's registered handle.
	 * @return string
	 */
	public function defer_pixel( $tag, $handle ) {
		if ( self::PIXEL_HANDLE !== $handle || false !== strpos( $tag, ' defer' ) ) {
			return $tag;
		}

		return str_replace( ' src=', ' defer src=', $tag );
	}

	/**
	 * Include all components for ecommerce tracking.
	 *
	 * @return void
	 */
	private function load_providers() {
		require_once __DIR__ . '/tracking-base.php';
		require_once __DIR__ . '/ecommerce/ecommerce-tracking.php';
		require_once __DIR__ . '/ecommerce/woocommerce.php';
		require_once __DIR__ . '/ecommerce/edd.php';
		require_once __DIR__ . '/forms/forms-tracking.php';
		require_once __DIR__ . '/forms/html-forms.php';

		SimpleStats_Tracking_WooCommerce::get_instance();
		SimpleStats_Tracking_EDD::get_instance();
		SimpleStats_Tracking_HtmlForms::get_instance();
	}

}
