<?php
/**
 * CDN Integration Module
 *
 * Provides CDN integration with Cloudflare, Bunny CDN, and generic webhooks.
 * Handles cache purging, tag-based invalidation, URL rewriting, and APO detection.
 *
 * @package Mamba\Modules\CDN
 * @since   1.0.0
 */

namespace Mamba\Modules\CDN;

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

use Mamba\Modules\CDN\Services\Manager;
use Mamba\Modules\CDN\Services\CdnMirror;
use Mamba\Modules\CDN\Services\Detectors;
use Mamba\Modules\CDN\Services\UrlRewriter;
use Mamba\Support\Logger;

/**
 * Class Module
 *
 * Main CDN module that initializes CDN services, registers settings,
 * and provides REST API endpoints for CDN management.
 *
 * @since 1.0.0
 */
final class Module {
    public function register(): void {
        // Initialize CDN services
        add_action('plugins_loaded', [__CLASS__, 'initServices'], 20);
        
        // Register admin hooks
        add_action('admin_init', [__CLASS__, 'registerSettings']);
        
        // Register REST API endpoints
        add_action('rest_api_init', [__CLASS__, 'registerRestEndpoints']);
    }
    
    /**
     * Initialize CDN services
     */
    public static function initServices(): void {
        // Initialize CDN manager
        Manager::init();
        
        // Initialize CDN mirror
        CdnMirror::init();
        
        // Initialize URL Rewriter
        UrlRewriter::init();
        
        // Add tag headers to responses
        add_action('send_headers', [__CLASS__, 'addTagHeaders'], 11);
        
        // Add tag headers to Store API responses
        add_filter('rest_post_dispatch', [__CLASS__, 'addStoreApiTagHeaders'], 10, 3);
    }
    
    /**
     * Register CDN settings
     */
    public static function registerSettings(): void {
        // CDN Provider
        register_setting('mamba_cdn', 'mamba_cdn_provider', ['type' => 'string', 'sanitize_callback' => 'sanitize_text_field', 'default' => 'disabled']);
        
        // Cloudflare settings
        register_setting('mamba_cdn', 'mamba_cloudflare_zone_id', ['type' => 'string', 'sanitize_callback' => 'sanitize_text_field', 'default' => '']);
        register_setting('mamba_cdn', 'mamba_cloudflare_api_token', ['type' => 'string', 'sanitize_callback' => 'sanitize_text_field', 'default' => '']);
        register_setting('mamba_cdn', 'mamba_cloudflare_detect_apo', ['type' => 'boolean', 'sanitize_callback' => 'rest_sanitize_boolean', 'default' => true]);
        register_setting('mamba_cdn', 'mamba_cloudflare_send_cache_tags', ['type' => 'boolean', 'sanitize_callback' => 'rest_sanitize_boolean', 'default' => true]);
        
        // Bunny settings
        register_setting('mamba_cdn', 'mamba_bunny_pull_zone_id', ['type' => 'string', 'sanitize_callback' => 'sanitize_text_field', 'default' => '']);
        register_setting('mamba_cdn', 'mamba_bunny_api_key', ['type' => 'string', 'sanitize_callback' => 'sanitize_text_field', 'default' => '']);
        register_setting('mamba_cdn', 'mamba_bunny_send_cdn_tags', ['type' => 'boolean', 'sanitize_callback' => 'rest_sanitize_boolean', 'default' => true]);
        register_setting('mamba_cdn', 'mamba_bunny_use_wildcard_purges', ['type' => 'boolean', 'sanitize_callback' => 'rest_sanitize_boolean', 'default' => false]);
        
        // Fastly settings
        register_setting('mamba_cdn', 'mamba_fastly_service_id', ['type' => 'string', 'sanitize_callback' => 'sanitize_text_field', 'default' => '']);
        register_setting('mamba_cdn', 'mamba_fastly_api_token', ['type' => 'string', 'sanitize_callback' => 'sanitize_text_field', 'default' => '']);
        register_setting('mamba_cdn', 'mamba_fastly_send_surrogate_keys', ['type' => 'boolean', 'sanitize_callback' => 'rest_sanitize_boolean', 'default' => true]);
        register_setting('mamba_cdn', 'mamba_fastly_soft_purge', ['type' => 'boolean', 'sanitize_callback' => 'rest_sanitize_boolean', 'default' => true]);
        
        // URL Rewriting settings (Push/Pull Zone Support)
        register_setting('mamba_cdn', 'mamba_cdn_enable_rewriting', ['type' => 'boolean', 'sanitize_callback' => 'rest_sanitize_boolean', 'default' => false]);
        register_setting('mamba_cdn', 'mamba_cdn_hostname', ['type' => 'string', 'sanitize_callback' => 'sanitize_text_field', 'default' => '']);
        register_setting('mamba_cdn', 'mamba_cdn_dirs', ['type' => 'array', 'sanitize_callback' => [__CLASS__, 'sanitizeStringArray'], 'default' => ['wp-content', 'wp-includes']]);
        register_setting('mamba_cdn', 'mamba_cdn_exclusions', ['type' => 'array', 'sanitize_callback' => [__CLASS__, 'sanitizeStringArray'], 'default' => ['.php', '.xml']]);
        
        // Generic webhook settings
        register_setting('mamba_cdn', 'mamba_generic_webhook_url', ['type' => 'string', 'sanitize_callback' => 'esc_url_raw', 'default' => '']);
        register_setting('mamba_cdn', 'mamba_generic_webhook_secret', ['type' => 'string', 'sanitize_callback' => 'sanitize_text_field', 'default' => '']);
        
        // Migrate CDN secrets to non-autoloaded
        self::migrateCdnSecretsToNonAutoloaded();
    }
    
    /**
     * Sanitize an array of strings
     * 
     * @param mixed $value The value to sanitize
     * @return array Sanitized array of strings
     */
    public static function sanitizeStringArray($value): array {
        if (!is_array($value)) {
            return [];
        }
        return array_map('sanitize_text_field', $value);
    }
    
    /**
     * Register REST API endpoints
     */
    public static function registerRestEndpoints(): void {
        register_rest_route('mamba-wc/v1', '/cdn/test-connection', [
            'methods' => 'POST',
            'callback' => [__CLASS__, 'testConnection'],
            'permission_callback' => function() {
                return current_user_can('manage_options');
            }
        ]);
        
        register_rest_route('mamba-wc/v1', '/cdn/test-purge', [
            'methods' => 'POST',
            'callback' => [__CLASS__, 'testPurge'],
            'permission_callback' => function() {
                return current_user_can('manage_options');
            }
        ]);
        
        register_rest_route('mamba-wc/v1', '/cdn/apply-recommended-settings', [
            'methods' => 'POST',
            'callback' => [__CLASS__, 'applyRecommendedSettings'],
            'permission_callback' => function() {
                return current_user_can('manage_options');
            }
        ]);
        
        register_rest_route('mamba-wc/v1', '/cdn/actions', [
            'methods' => 'GET',
            'callback' => [__CLASS__, 'getActions'],
            'permission_callback' => function() {
                return current_user_can('manage_options');
            }
        ]);
    }
    
    /**
     * Add tag headers to responses
     */
    public static function addTagHeaders(): void {
        if (!Manager::isEnabled()) return;
        
        try {
            $tags = \Mamba\Modules\Caching\Services\Tags::detectForCurrentRequest();
            if (empty($tags)) return;
        } catch (\Exception $e) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log('Mamba CDN: Tag detection failed: ' . $e->getMessage());
            }
            return;
        }
        
        $providerName = Manager::getProviderName();
        $tagString = implode(',', $tags);
        
        switch ($providerName) {
            case 'cloudflare':
                if (get_option('mamba_cloudflare_send_cache_tags', true)) {
                    header('Cache-Tag: ' . $tagString, false);
                }
                break;
                
            case 'bunny':
                if (get_option('mamba_bunny_send_cdn_tags', true)) {
                    header('CDN-Tag: ' . $tagString, false);
                }
                break;
                
            case 'fastly':
                if (get_option('mamba_fastly_send_surrogate_keys', true)) {
                    // Fastly uses space-separated Surrogate-Key header
                    header('Surrogate-Key: ' . str_replace(',', ' ', $tagString), false);
                }
                break;
        }
    }
    
    /**
     * Generate header combinations for APO/custom cache keys
     */
    public static function generateHeaderCombos(): array {
        if (Manager::getProviderName() !== 'cloudflare') {
            return [];
        }
        
        return Detectors::generateCloudflareHeaderCombos();
    }
    
    /**
     * Add tag headers to Store API responses
     */
    public static function addStoreApiTagHeaders($result, $server, $request): mixed {
        if (!Manager::isEnabled()) return $result;
        
        if (strpos($request->get_route(), '/wc/store/') !== 0) {
            return $result;
        }
        
        try {
            // Generate tags for Store API response
            $tags = self::generateStoreApiTags($request, $result);
            if (empty($tags)) return $result;
        } catch (\Exception $e) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log('Mamba CDN: Store API tag generation failed: ' . $e->getMessage());
            }
            return $result;
        }
        
        $providerName = Manager::getProviderName();
        $tagString = implode(',', $tags);
        
        switch ($providerName) {
            case 'cloudflare':
                if (get_option('mamba_cloudflare_send_cache_tags', true)) {
                    $result->header('Cache-Tag', $tagString);
                }
                break;
                
            case 'bunny':
                if (get_option('mamba_bunny_send_cdn_tags', true)) {
                    $result->header('CDN-Tag', $tagString);
                }
                break;
                
            case 'fastly':
                if (get_option('mamba_fastly_send_surrogate_keys', true)) {
                    // Fastly uses space-separated Surrogate-Key header
                    $result->header('Surrogate-Key', str_replace(',', ' ', $tagString));
                }
                break;
        }
        
        return $result;
    }
    
    /**
     * Generate tags for Store API response
     */
    private static function generateStoreApiTags($request, $result): array {
        $tags = ['store_api'];
        
        // Add endpoint-specific tags
        $route = $request->get_route();
        if (strpos($route, '/wc/store/v1/products') !== false) {
            $tags[] = 'store_api_products';
        } elseif (strpos($route, '/wc/store/v1/categories') !== false) {
            $tags[] = 'store_api_categories';
        } elseif (strpos($route, '/wc/store/v1/product-collection') !== false) {
            $tags[] = 'store_api_catalog';
        } elseif (strpos($route, '/wc/store/v1/cart') !== false) {
            $tags[] = 'store_api_cart';
        } elseif (strpos($route, '/wc/store/v1/checkout') !== false) {
            $tags[] = 'store_api_checkout';
        }
        
        // Add product tags if products are in the response
        if (method_exists($result, 'get_data')) {
            $data = $result->get_data();
            if (isset($data['id'])) {
                $tags[] = 'product_' . $data['id'];
            } elseif (isset($data[0]['id'])) {
                foreach ($data as $item) {
                    if (isset($item['id'])) {
                        $tags[] = 'product_' . $item['id'];
                    }
                }
            }
        }
        
        return array_unique($tags);
    }
    
    /**
     * Test CDN connection
     */
    public static function testConnection(\WP_REST_Request $request): \WP_REST_Response {
        $provider = Manager::getProvider();
        if (!$provider) {
            Logger::warning('CDN connection test failed: No provider configured');
            return new \WP_REST_Response(['success' => false, 'message' => 'No CDN provider configured'], 400);
        }
        
        $result = $provider->testConnection();
        
        Logger::info('CDN connection test', [
            'provider' => Manager::getProviderName(),
            'success' => $result->isSuccess(),
            'message' => $result->getMessage()
        ]);
        
        return new \WP_REST_Response([
            'success' => $result->isSuccess(),
            'message' => $result->getMessage(),
            'data' => $result->getData()
        ]);
    }
    
    /**
     * Test CDN purge
     */
    public static function testPurge(\WP_REST_Request $request): \WP_REST_Response {
        $provider = Manager::getProvider();
        if (!$provider) {
            Logger::warning('CDN purge test failed: No provider configured');
            return new \WP_REST_Response(['success' => false, 'message' => 'No CDN provider configured'], 400);
        }
        
        $type = $request->get_param('type') ?: 'url';
        $testUrl = home_url('/');
        
        if ($type === 'tag') {
            $result = $provider->purgeTags(['test_tag']);
        } else {
            $result = $provider->purgeUrls([$testUrl]);
        }
        
        Logger::info('CDN purge test', [
            'provider' => Manager::getProviderName(),
            'type' => $type,
            'success' => $result->isSuccess()
        ]);
        
        return new \WP_REST_Response([
            'success' => $result->isSuccess(),
            'message' => $result->getMessage(),
            'data' => $result->getData()
        ]);
    }
    
    /**
     * Apply recommended settings
     */
    public static function applyRecommendedSettings(\WP_REST_Request $request): \WP_REST_Response {
        $provider = Manager::getProvider();
        if (!$provider) {
            return new \WP_REST_Response(['success' => false, 'message' => 'No CDN provider configured'], 400);
        }
        
        $result = $provider->applyRecommendedSettings();
        
        return new \WP_REST_Response([
            'success' => $result->isSuccess(),
            'message' => $result->getMessage(),
            'data' => $result->getData()
        ]);
    }
    
    /**
     * Get CDN actions
     */
    public static function getActions(\WP_REST_Request $request): \WP_REST_Response {
        $actions = \Mamba\Modules\CDN\Services\CdnMirror::getActionLog();
        
        return new \WP_REST_Response([
            'success' => true,
            'actions' => $actions
        ]);
    }
    
    /**
     * Migrate CDN secrets to non-autoloaded for security and performance
     */
    private static function migrateCdnSecretsToNonAutoloaded(): void {
        // Check if migration has already been completed
        if (get_option('mamba_cdn_autoload_migrated')) {
            return;
        }
        
        global $wpdb;
        
        // CDN secrets that should be non-autoloaded
        $cdnSecrets = [
            'mamba_cloudflare_zone_id',
            'mamba_cloudflare_api_token',
            'mamba_bunny_pull_zone_id',
            'mamba_bunny_api_key',
            'mamba_generic_webhook_url',
            'mamba_generic_webhook_secret',
            'mamba_cloudflare_apo_status',
            'mamba_cloudflare_rocket_loader_status'
        ];
        
        // Build placeholders for prepared statement
        $placeholders = implode(',', array_fill(0, count($cdnSecrets), '%s'));
        
        // Update autoload to 'no' for CDN secrets
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $result = $wpdb->query($wpdb->prepare(
            "UPDATE {$wpdb->options} 
             SET autoload = 'no' 
             WHERE option_name IN ($placeholders) 
             AND autoload = 'yes'",
            $cdnSecrets
        ));
        
        // Mark migration as completed
        update_option('mamba_cdn_autoload_migrated', 1, true);
        
        // Log migration for debugging
        if (defined('WP_DEBUG') && WP_DEBUG && $result !== false) {
            error_log('Mamba CDN: Migrated ' . $result . ' CDN secret options to non-autoloaded');
        }
    }
}
