<?php

/**
 * CSS Path Rewriter Service
 *
 * Handles rewriting of URLs in CSS when files are moved
 *
 * @package ProRank\SEO\Core\Optimization\CSS
 * @since   1.0.0
 */

declare(strict_types=1);

namespace ProRank\SEO\Core\Optimization\CSS;

use MatthiasMullie\PathConverter\Converter;

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


/**
 * CssPathRewriterService class
 */


class CssPathRewriterService {
    
    /**
     * Rewrite URLs in CSS content
     *
     * @param string $content CSS content
     * @param string $source_path Original file path
     * @param string $target_path New file path
     * @return string CSS with rewritten URLs
     */
    public function rewrite(string $content, string $source_path, string $target_path): string {
        // Skip if paths are the same
        if ($source_path === $target_path) {
            return $content;
        }
        
        $this->ensurePathConverterLibrary();
        
        // Create path converter
        $converter = new Converter($source_path, $target_path);
        
        // Find and replace URLs
        $content = $this->rewriteUrls($content, $converter);
        
        // Find and replace @import statements
        $content = $this->rewriteImports($content, $converter);
        
        return $content;
    }

    /**
     * Ensure the Matthias Mullie path converter classes are loaded.
     *
     * @throws \RuntimeException When the library cannot be loaded.
     */
    private function ensurePathConverterLibrary(): void {
        if ( class_exists( Converter::class ) ) {
            return;
        }

        $base = dirname( __DIR__, 3 ) . '/lib/MatthiasMullie/PathConverter/';
        $files = [
            'ConverterInterface.php',
            'NoConverter.php',
            'Converter.php',
        ];

        foreach ( $files as $file ) {
            $path = $base . $file;
            if ( file_exists( $path ) ) {
                require_once $path;
            }
        }

        if ( ! class_exists( Converter::class ) ) {
            throw new \RuntimeException( 'ProRank CSS Path Rewriter Error: MatthiasMullie PathConverter library not found.' );
        }
    }
    
    /**
     * Rewrite url() references in CSS
     *
     * @param string $content CSS content
     * @param Converter $converter Path converter instance
     * @return string CSS with rewritten URLs
     */
    private function rewriteUrls(string $content, Converter $converter): string {
        $pattern = '/url\(\s*["\']?(?<url>[^"\')]+)["\']?\s*\)/i';
        
        return preg_replace_callback($pattern, function($matches) use ($converter) {
            $url = $matches['url'];
            
            // Skip data URIs, absolute URLs, and root-relative URLs
            if ($this->shouldSkipUrl($url)) {
                return $matches[0];
            }
            
            // Convert the relative path
            $converted = $converter->convert($url);
            
            // Rebuild the url() statement
            return 'url(' . $this->quoteUrl($converted) . ')';
        }, $content);
    }
    
    /**
     * Rewrite @import statements in CSS
     *
     * @param string $content CSS content
     * @param Converter $converter Path converter instance
     * @return string CSS with rewritten imports
     */
    private function rewriteImports(string $content, Converter $converter): string {
        // Pattern for @import url()
        $pattern1 = '/@import\s+url\(\s*["\']?(?<url>[^"\')]+)["\']?\s*\)(?<media>[^;]*);?/i';
        $content = preg_replace_callback($pattern1, function($matches) use ($converter) {
            $url = $matches['url'];
            
            if ($this->shouldSkipUrl($url)) {
                return $matches[0];
            }
            
            $converted = $converter->convert($url);
            $media = trim($matches['media']);
            
            return '@import url(' . $this->quoteUrl($converted) . ')' . 
                   ($media ? ' ' . $media : '') . ';';
        }, $content);
        
        // Pattern for @import "..."
        $pattern2 = '/@import\s+["\'](?<url>[^"\']+)["\'](?<media>[^;]*);?/i';
        $content = preg_replace_callback($pattern2, function($matches) use ($converter) {
            $url = $matches['url'];
            
            if ($this->shouldSkipUrl($url)) {
                return $matches[0];
            }
            
            $converted = $converter->convert($url);
            $media = trim($matches['media']);
            
            return '@import "' . $converted . '"' . 
                   ($media ? ' ' . $media : '') . ';';
        }, $content);
        
        return $content;
    }
    
    /**
     * Check if URL should be skipped from rewriting
     *
     * @param string $url URL to check
     * @return bool True if should skip
     */
    private function shouldSkipUrl(string $url): bool {
        // Skip empty URLs
        if (empty($url)) {
            return true;
        }
        
        // Skip data URIs
        if (strpos($url, 'data:') === 0) {
            return true;
        }
        
        // Skip absolute URLs (http://, https://, //)
        if (preg_match('/^(https?:)?\/\//i', $url)) {
            return true;
        }
        
        // Skip root-relative URLs
        if (strpos($url, '/') === 0) {
            return true;
        }
        
        // Skip hash URLs
        if (strpos($url, '#') === 0) {
            return true;
        }
        
        return false;
    }
    
    /**
     * Quote URL if necessary
     *
     * @param string $url URL to quote
     * @return string Quoted URL if needed
     */
    private function quoteUrl(string $url): string {
        // URLs with certain characters should be quoted
        if (preg_match('/[\s\(\)\'"]/', $url)) {
            return '"' . str_replace('"', '\\"', $url) . '"';
        }
        
        return $url;
    }
    
    /**
     * Convert URL to absolute path
     *
     * @param string $url URL to convert
     * @param string $base_url Base URL for relative paths
     * @return string Absolute URL
     */
    public function makeAbsolute(string $url, string $base_url): string {
        // Already absolute
        if (preg_match('/^(https?:)?\/\//i', $url)) {
            return $url;
        }
        
        // Root relative
        if (strpos($url, '/') === 0) {
            $parsed = wp_parse_url($base_url);
            $scheme = (string) ($parsed['scheme'] ?? wp_parse_url(home_url('/'), PHP_URL_SCHEME) ?? (is_ssl() ? 'https' : 'http'));
            $host = (string) ($parsed['host'] ?? wp_parse_url(home_url('/'), PHP_URL_HOST) ?? '');
            if ($host === '') {
                return home_url($url);
            }
            return $scheme . '://' . $host . $url;
        }
        
        // Relative to current directory
        return rtrim($base_url, '/') . '/' . ltrim($url, '/');
    }
    
    /**
     * Extract all URLs from CSS content
     *
     * @param string $content CSS content
     * @return array Array of URLs found
     */
    public function extractUrls(string $content): array {
        $urls = [];
        
        // Extract from url()
        preg_match_all('/url\(\s*["\']?([^"\')]+)["\']?\s*\)/i', $content, $matches);
        if (!empty($matches[1])) {
            $urls = array_merge($urls, $matches[1]);
        }
        
        // Extract from @import
        preg_match_all('/@import\s+url\(\s*["\']?([^"\')]+)["\']?\s*\)/i', $content, $matches);
        if (!empty($matches[1])) {
            $urls = array_merge($urls, $matches[1]);
        }
        
        preg_match_all('/@import\s+["\']([^"\']+)["\']/i', $content, $matches);
        if (!empty($matches[1])) {
            $urls = array_merge($urls, $matches[1]);
        }

        $site_host = wp_parse_url(\home_url(), PHP_URL_HOST);

        // Filter out data/hash URLs and keep only local (same-host) assets
        $urls = array_filter($urls, function($url) use ($site_host) {
            if (empty($url)) {
                return false;
            }

            if (strpos($url, 'data:') === 0 || strpos($url, '#') === 0) {
                return false;
            }

            // Allow same-site absolute/protocol-relative URLs, skip external
            if (preg_match('/^(https?:)?\\/\\//i', $url)) {
                $host = wp_parse_url($url, PHP_URL_HOST);
                return $host && $site_host && strcasecmp($host, $site_host) === 0;
            }

            return true;
        });

        return array_unique($urls);
    }
}
