<?php
/**
 * Google Site Kit Integration
 *
 * Prevents Google Site Kit from firing analytics/tracking requests
 * before user consent is obtained. Site Kit loads its own consent-mode
 * script which initializes gtag and sends measurement pings even in
 * "denied" state — this still constitutes data transfer to Google
 * which requires consent under GDPR/ePrivacy.
 *
 * This class:
 * 1. Dequeues Site Kit's consent-mode and analytics scripts on page load
 * 2. Re-enqueues them via JS callback once analytics consent is granted
 *
 * @package Biscotti_CMP
 * @since 3.7.0
 */

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

class Biscotti_Google_Sitekit
{
    /**
     * Site Kit script handles that must be blocked until consent
     */
    private const BLOCKED_HANDLES = [
        'google_gtagjs',
        'googlesitekit-consent-mode',
        'googlesitekit-events-provider',
        'googlesitekit_modules_tagmanager',
        'googlesitekit_modules_analytics-4',
    ];

    /**
     * Pattern matches for Site Kit script handles (prefix matching)
     */
    private const BLOCKED_HANDLE_PREFIXES = [
        'googlesitekit-',
        'google_gtagjs',
    ];

    /**
     * Initialize hooks
     */
    public function __construct()
    {
        // Only run on frontend, not admin
        if (is_admin()) {
            return;
        }

        // Run late (priority 999) to ensure Site Kit has already enqueued its scripts
        add_action('wp_enqueue_scripts', [$this, 'block_sitekit_scripts'], 999);
        add_action('wp_head', [$this, 'inject_consent_restore_script'], 1);
    }

    /**
     * Dequeue all Site Kit tracking scripts until consent is given.
     * This runs AFTER Site Kit has enqueued its scripts (priority 999).
     */
    public function block_sitekit_scripts()
    {
        // Only act if Site Kit is active
        if (!defined('GOOGLESITEKIT_VERSION')) {
            return;
        }

        global $wp_scripts;
        if (empty($wp_scripts->registered)) {
            return;
        }

        $blocked = [];

        foreach ($wp_scripts->registered as $handle => $script) {
            if ($this->should_block_handle($handle, $script)) {
                wp_dequeue_script($handle);
                $blocked[] = $handle;
            }
        }

        // Blocked handles are dequeued above; no debug logging in production.
        unset($blocked);
    }

    /**
     * Check if a script handle should be blocked
     */
    private function should_block_handle(string $handle, $script): bool
    {
        // Exact match
        if (in_array($handle, self::BLOCKED_HANDLES, true)) {
            return true;
        }

        // Prefix match
        foreach (self::BLOCKED_HANDLE_PREFIXES as $prefix) {
            if (strpos($handle, $prefix) === 0) {
                return true;
            }
        }

        // URL-based match: block any script loading from google-site-kit plugin directory
        // that contains analytics, gtag, or consent-mode
        if (isset($script->src) && is_string($script->src)) {
            if (
                strpos($script->src, 'google-site-kit') !== false &&
                (
                    strpos($script->src, 'consent-mode') !== false ||
                    strpos($script->src, 'analytics') !== false ||
                    strpos($script->src, 'tagmanager') !== false ||
                    strpos($script->src, 'gtag') !== false ||
                    strpos($script->src, 'events-provider') !== false
                )
            ) {
                return true;
            }
        }

        return false;
    }

    /**
     * Inject a small inline script that re-enables Site Kit after consent.
     * This listens for Biscotti's consent event and dynamically loads the
     * blocked Site Kit scripts.
     */
    public function inject_consent_restore_script()
    {
        if (!defined('GOOGLESITEKIT_VERSION')) {
            return;
        }

        // Collect the URLs of blocked scripts so JS can reload them after consent
        global $wp_scripts;
        $blocked_urls = [];

        if (!empty($wp_scripts->registered)) {
            foreach ($wp_scripts->registered as $handle => $script) {
                if ($this->should_block_handle($handle, $script) && !empty($script->src)) {
                    $src = $script->src;
                    // Handle protocol-relative and relative URLs
                    if (strpos($src, '//') === 0) {
                        $src = 'https:' . $src;
                    } elseif (strpos($src, '/') === 0) {
                        $src = home_url($src);
                    }
                    // Add version if present
                    if (!empty($script->ver)) {
                        $src .= (strpos($src, '?') !== false ? '&' : '?') . 'ver=' . $script->ver;
                    }
                    $blocked_urls[] = $src;
                }
            }
        }

        if (empty($blocked_urls)) {
            return;
        }

        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wp_json_encode produces safe JS literal
        $restore_js = sprintf(
            '(function(){var urls=%s;var loaded=false;function loadSiteKit(){if(loaded)return;loaded=true;urls.forEach(function(url){var s=document.createElement("script");s.src=url;s.async=true;document.head.appendChild(s);});}if(window.Biscotti&&window.Biscotti.on){window.Biscotti.on("consent",function(c){if(c&&c.analytics)loadSiteKit();});}document.addEventListener("biscotti:consent",function(e){var d=e.detail||{};if(d.analytics)loadSiteKit();});try{var stored=localStorage.getItem("biscotti_consent")||document.cookie.match(/biscotti_consent=([^;]+)/);if(stored){var consent=JSON.parse(typeof stored==="string"?stored:decodeURIComponent(stored[1]));if(consent&&consent.analytics)loadSiteKit();}}catch(e){}})();',
            wp_json_encode($blocked_urls)
        );
        wp_add_inline_script('biscotti-widget', $restore_js, 'after');
    }
}
