<?php
/**
 * CDN URL Rewriter Service
 *
 * Rewrites local asset URLs to CDN URLs for Pull Zone configurations,
 * enabling static asset delivery through CDN edge servers.
 *
 * @package Mamba\Modules\CDN\Services
 * @since   1.0.0
 */

namespace Mamba\Modules\CDN\Services;

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

/**
 * Class UrlRewriter
 *
 * Rewrites local asset URLs to CDN URLs for Pull Zone configurations
 * (Bunny, Generic). Supports configurable directories and exclusions.
 *
 * @since 1.0.0
 */
final class UrlRewriter {
    private string $cdnHostname;
    private array $dirs;
    private array $exclusions;
    
    public function __construct(string $cdnHostname, array $dirs = [], array $exclusions = []) {
        $this->cdnHostname = rtrim($cdnHostname, '/');
        // Ensure protocol presence
        if (!preg_match('~^https?://~', $this->cdnHostname)) {
            $this->cdnHostname = 'https://' . $this->cdnHostname;
        }
        
        $this->dirs = $dirs ?: ['wp-content', 'wp-includes'];
        $this->exclusions = $exclusions;
    }

    public static function init(): void {
        // Only run if CDN rewriting is enabled
        if (!get_option('mamba_cdn_enable_rewriting', 0)) {
            return;
        }

        $hostname = get_option('mamba_cdn_hostname', '');
        if (empty($hostname)) {
            return;
        }
        
        // Don't rewrite in admin, login, or during AJAX unless it's a specific frontend action
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized via sanitize_text_field
        $requestUri = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : '';
        if (is_admin() || 
            (defined('DOING_AJAX') && DOING_AJAX && !apply_filters('mamba_cdn_rewrite_in_ajax', false)) || 
            (defined('DOING_CRON') && DOING_CRON) ||
            stripos($requestUri, 'wp-login.php') !== false) {
            return;
        }
        
        $instance = new self(
            $hostname,
            get_option('mamba_cdn_dirs', ['wp-content', 'wp-includes']),
            get_option('mamba_cdn_exclusions', ['.php', '.xml'])
        );
        
        $instance->registerHooks();
    }

    public function registerHooks(): void {
        // Asset URL filters
        add_filter('theme_file_uri', [$this, 'rewriteUrl'], 99);
        add_filter('parent_theme_file_uri', [$this, 'rewriteUrl'], 99);
        add_filter('wp_get_attachment_url', [$this, 'rewriteUrl'], 99);
        add_filter('style_loader_src', [$this, 'rewriteUrl'], 99);
        add_filter('script_loader_src', [$this, 'rewriteUrl'], 99);
        
        // Content buffering for hardcoded assets (Enterprise Feature)
        if (get_option('mamba_cdn_buffer_rewriting', 0)) {
            add_action('template_redirect', [$this, 'startBuffer'], 1);
        }
    }

    public function startBuffer(): void {
        ob_start([$this, 'rewriteContent']);
        
        // Register shutdown handler to ensure buffer is explicitly flushed
        // This guarantees the buffer is closed even if WordPress exits unexpectedly
        register_shutdown_function(function () {
            if (ob_get_level() > 0) {
                ob_end_flush();
            }
        });
    }

    public function rewriteContent(string $buffer): string {
        // Get site domain to look for
        $siteUrl = home_url();
        $domain = parse_url($siteUrl, PHP_URL_HOST);
        
        // Build regex to find local assets
        // Matches: quote + (http/s + domain + / + dir + rest) + quote
        $dirsRegex = implode('|', array_map('preg_quote', $this->dirs));
        
        // Simple regex to replace base URL in known directories
        // We use the 'dirs' array to target wp-content/wp-includes
        // This is a "dumb" replacement that is fast and covers 90% of cases
        // <img src="https://mysite.com/wp-content/..." -> "https://cdn.com/wp-content/..."
        
        // Find: (https?://mysite.com)(/wp-content|/wp-includes)
        // Repl: cdnHostname$2
        
        $pattern = '~(' . preg_quote($siteUrl, '~') . ')(/(' . $dirsRegex . ')/[^"\']+)~i';
        
        return preg_replace_callback($pattern, function($matches) {
            return $this->rewriteUrl($matches[0]);
        }, $buffer);
    }

    public function rewriteUrl(string $url): string {
        // Skip if already on CDN
        if (strpos($url, $this->cdnHostname) !== false) {
            return $url;
        }
        
        // Check exclusions
        foreach ($this->exclusions as $ex) {
            if (stripos($url, $ex) !== false) {
                return $url;
            }
        }
        
        // Check directories
        $found = false;
        foreach ($this->dirs as $dir) {
            if (strpos($url, '/' . $dir . '/') !== false) {
                $found = true;
                break;
            }
        }
        if (!$found) return $url;
        
        // Perform replacement
        return str_replace(home_url(), $this->cdnHostname, $url);
    }
}
