<?php
/**
 * Livada SEO — Analytics Module
 *
 * Injects third-party tracking scripts into wp_head (priority 99, after all
 * SEO meta) for GA4, Matomo, Microsoft Clarity, and an optional custom script.
 *
 * Each provider is independent: any combination can be enabled at once.
 * Scripts are skipped entirely on the admin side and for logged-in users
 * who hold the manage_options capability (when analytics_exclude_admins is true).
 *
 * @package Livada_SEO
 */

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

class Livada_SEO_Analytics {

	// ── Bootstrap ─────────────────────────────────────────────────────────────

	/**
	 * Registers all hooks for this module.
	 * Called once by Livada_SEO_Loader::init().
	 */
	public static function init(): void {
		// Priority 99: output after all SEO meta tags (wp_head default is 10).
		add_action( 'wp_head', [ self::class, 'output_tracking_scripts' ], 99 );
	}

	// ── Output ────────────────────────────────────────────────────────────────

	/**
	 * Outputs all enabled tracking snippets into <head>.
	 *
	 * Skips output:
	 *   - On any admin page.
	 *   - For users with manage_options, when analytics_exclude_admins is true.
	 */
	public static function output_tracking_scripts(): void {
		// Never inject scripts in the WordPress admin.
		if ( is_admin() ) {
			return;
		}

		// Skip admins/managers to avoid inflating analytics stats.
		$exclude_admins = Livada_SEO_Loader::get_setting( 'analytics_exclude_admins', true );
		if ( $exclude_admins && current_user_can( 'manage_options' ) ) {
			return;
		}

		self::maybe_output_ga4();
		self::maybe_output_matomo();
		self::maybe_output_clarity();
		self::maybe_output_custom_head();
	}

	// ── GA4 ───────────────────────────────────────────────────────────────────

	/**
	 * Outputs the Google Analytics 4 gtag.js snippet when a valid GA4 ID is set.
	 *
	 * ID format validation: must match /^G-[A-Z0-9]+$/.
	 */
	private static function maybe_output_ga4(): void {
		$ga4_id = (string) Livada_SEO_Loader::get_setting( 'analytics_ga4_id', '' );

		if ( '' === $ga4_id ) {
			return;
		}

		// Validate GA4 measurement ID format before output.
		if ( ! preg_match( '/^G-[A-Z0-9]+$/', $ga4_id ) ) {
			return;
		}

		$escaped_id = esc_attr( $ga4_id );

		echo "\n<!-- Livada SEO: Google Analytics 4 -->\n";
		echo '<script async src="https://www.googletagmanager.com/gtag/js?id=' . $escaped_id . '"></script>' . "\n";
		echo '<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}gtag(\'js\',new Date());gtag(\'config\',\'' . $escaped_id . '\');</script>' . "\n";
	}

	// ── Matomo ────────────────────────────────────────────────────────────────

	/**
	 * Outputs the Matomo self-hosted tracking snippet when both URL and site ID
	 * are configured.
	 *
	 * Matomo URL is sanitized through esc_url(); site ID is cast to integer.
	 */
	private static function maybe_output_matomo(): void {
		$matomo_url     = (string) Livada_SEO_Loader::get_setting( 'analytics_matomo_url', '' );
		$matomo_site_id = (string) Livada_SEO_Loader::get_setting( 'analytics_matomo_site_id', '' );

		if ( '' === $matomo_url || '' === $matomo_site_id ) {
			return;
		}

		// Validate and sanitize Matomo URL.
		$safe_url = esc_url( $matomo_url );
		if ( '' === $safe_url ) {
			return;
		}

		// Ensure trailing slash so matomo.php / matomo.js paths are correct.
		$safe_url = rtrim( $safe_url, '/' ) . '/';

		// Site ID must be a positive integer.
		$site_id = absint( $matomo_site_id );
		if ( 0 === $site_id ) {
			return;
		}

		echo "\n<!-- Livada SEO: Matomo -->\n";
		echo '<script>';
		echo 'var _paq=window._paq=window._paq||[];';
		echo '_paq.push([\'trackPageView\']);';
		echo '_paq.push([\'enableLinkTracking\']);';
		echo '(function(){';
		echo 'var u="' . esc_js( $safe_url ) . '";';
		echo '_paq.push([\'setTrackerUrl\',u+\'matomo.php\']);';
		echo '_paq.push([\'setSiteId\',\'' . esc_js( (string) $site_id ) . '\']);';
		echo 'var d=document,g=d.createElement(\'script\'),s=d.getElementsByTagName(\'script\')[0];';
		echo 'g.async=true;g.src=u+\'matomo.js\';';
		echo 's.parentNode.insertBefore(g,s);';
		echo '})();';
		echo '</script>' . "\n";
	}

	// ── Microsoft Clarity ─────────────────────────────────────────────────────

	/**
	 * Outputs the Microsoft Clarity snippet when a valid Clarity project ID is set.
	 *
	 * ID format validation: must match /^[a-z0-9]+$/i.
	 */
	private static function maybe_output_clarity(): void {
		$clarity_id = (string) Livada_SEO_Loader::get_setting( 'analytics_clarity_id', '' );

		if ( '' === $clarity_id ) {
			return;
		}

		// Validate Clarity project ID format before output.
		if ( ! preg_match( '/^[a-z0-9]+$/i', $clarity_id ) ) {
			return;
		}

		$escaped_id = esc_js( $clarity_id );

		echo "\n<!-- Livada SEO: Microsoft Clarity -->\n";
		echo '<script>(function(c,l,a,r,i,t,y){';
		echo 'c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};';
		echo 't=l.createElement(r);t.async=1;';
		echo 't.src="https://www.clarity.ms/tag/"+"' . $escaped_id . '";';
		echo 'y=l.getElementsByTagName(r)[0];';
		echo 'y.parentNode.insertBefore(t,y);';
		echo '})(window,document,"clarity","script","' . $escaped_id . '");</script>' . "\n";
	}

	// ── Custom head script ────────────────────────────────────────────────────

	/**
	 * Outputs the custom head script saved in settings.
	 *
	 * This value is written only by users who hold manage_options (via the plugin
	 * settings form), so it is treated as trusted admin content.  We use wp_kses()
	 * with a permissive <script> allowlist as a defence-in-depth measure against
	 * accidental DB tampering, while still allowing any valid tracking snippet.
	 */
	private static function maybe_output_custom_head(): void {
		$custom = (string) Livada_SEO_Loader::get_setting( 'analytics_custom_head', '' );

		if ( '' === $custom ) {
			return;
		}

		// Allowed tags: <script> with all standard attributes.
		$allowed_tags = [
			'script' => [
				'type'  => true,
				'src'   => true,
				'async' => true,
				'defer' => true,
				'id'    => true,
				'nonce' => true,
			],
		];

		echo "\n<!-- Livada SEO: Custom head script -->\n";
		echo wp_kses( $custom, $allowed_tags ) . "\n";
	}
}
