<?php
/**
 * Fastly CDN Adapter
 *
 * Implements CDN provider interface for Fastly integration including
 * URL purging, Surrogate-Key (tag) based purging, and instant purge support.
 *
 * @package Mamba\Modules\CDN\Services
 * @since   1.0.0
 */

namespace Mamba\Modules\CDN\Services;

/**
 * Class FastlyAdapter
 *
 * Fastly CDN adapter that handles cache purging via the Fastly API,
 * supports Surrogate-Key headers for tag-based invalidation, and provides
 * instant purge capabilities ideal for WooCommerce stock/pricing updates.
 *
 * @since 1.0.0
 */
final class FastlyAdapter implements Provider {
    private string $serviceId;
    private string $apiToken;
    private bool $sendSurrogateKeys;
    private bool $softPurge;
    private const API_BASE = 'https://api.fastly.com';
    
    public function __construct(
        string $serviceId,
        string $apiToken,
        bool $sendSurrogateKeys = true,
        bool $softPurge = true
    ) {
        $this->serviceId = $serviceId;
        $this->apiToken = $apiToken;
        $this->sendSurrogateKeys = $sendSurrogateKeys;
        $this->softPurge = $softPurge;
    }
    
    public function isConnected(): bool {
        return !empty($this->serviceId) && !empty($this->apiToken);
    }
    
    public function getName(): string {
        return 'fastly';
    }
    
    public function purgeUrls(array $urls, array $headerCombos = []): Result {
        if (empty($urls)) {
            return Result::success('No URLs to purge');
        }
        
        $firstError = null;
        
        foreach (array_unique($urls) as $url) {
            $result = $this->purgeUrl($url);
            if (!$result->isSuccess() && $firstError === null) {
                $firstError = $result;
            }
        }
        
        return $firstError ?: Result::success('URL purge successful');
    }
    
    /**
     * Purge a single URL via Fastly's purge endpoint
     */
    private function purgeUrl(string $url): Result {
        $args = [
            'method' => 'PURGE',
            'headers' => [
                'Fastly-Key' => $this->apiToken,
                'User-Agent' => 'Mamba-WooCommerce-CDN/1.0'
            ],
            'timeout' => 30,
            'sslverify' => true
        ];
        
        // Soft purge marks content as stale but serves it while revalidating
        if ($this->softPurge) {
            $args['headers']['Fastly-Soft-Purge'] = '1';
        }
        
        $response = wp_remote_request($url, $args);
        
        if (is_wp_error($response)) {
            return Result::error('Purge request failed: ' . $response->get_error_message());
        }
        
        $statusCode = wp_remote_retrieve_response_code($response);
        
        if ($statusCode >= 200 && $statusCode < 300) {
            return Result::success('URL purged successfully');
        }
        
        $body = wp_remote_retrieve_body($response);
        return Result::error("Purge failed with status {$statusCode}: {$body}", $statusCode);
    }
    
    public function purgeTags(array $tags): Result {
        if (empty($tags)) {
            return Result::success('No tags to purge');
        }
        
        // Fastly uses Surrogate-Key for tag-based purging
        // API endpoint: POST /service/{service_id}/purge
        // Header: Surrogate-Key: tag1 tag2 tag3 (space-separated)
        
        // Fastly allows up to 256 surrogate keys per purge request
        $chunks = array_chunk(array_values(array_unique($tags)), 256);
        $firstError = null;
        
        foreach ($chunks as $chunk) {
            $result = $this->purgeSurrogateKeys($chunk);
            if (!$result->isSuccess() && $firstError === null) {
                $firstError = $result;
            }
        }
        
        return $firstError ?: Result::success('Tag purge successful');
    }
    
    /**
     * Purge by Surrogate-Key (Fastly's tag system)
     */
    private function purgeSurrogateKeys(array $keys): Result {
        $url = self::API_BASE . "/service/{$this->serviceId}/purge";
        
        $args = [
            'method' => 'POST',
            'headers' => [
                'Fastly-Key' => $this->apiToken,
                'Surrogate-Key' => implode(' ', $keys),
                'Content-Type' => 'application/json',
                'User-Agent' => 'Mamba-WooCommerce-CDN/1.0'
            ],
            'timeout' => 30,
            'sslverify' => true
        ];
        
        // Soft purge for graceful invalidation
        if ($this->softPurge) {
            $args['headers']['Fastly-Soft-Purge'] = '1';
        }
        
        $response = wp_remote_request($url, $args);
        
        if (is_wp_error($response)) {
            return Result::error('Tag purge request failed: ' . $response->get_error_message());
        }
        
        $statusCode = wp_remote_retrieve_response_code($response);
        $body = wp_remote_retrieve_body($response);
        $data = json_decode($body, true);
        
        if ($statusCode >= 200 && $statusCode < 300) {
            return Result::success('Tag purge successful', $data ?: []);
        }
        
        $errorMessage = 'Tag purge failed';
        if ($data && isset($data['msg'])) {
            $errorMessage = $data['msg'];
        }
        
        return Result::error($errorMessage, $statusCode, $data ?: []);
    }
    
    public function purgeAll(): Result {
        $url = self::API_BASE . "/service/{$this->serviceId}/purge_all";
        
        $args = [
            'method' => 'POST',
            'headers' => [
                'Fastly-Key' => $this->apiToken,
                'Content-Type' => 'application/json',
                'User-Agent' => 'Mamba-WooCommerce-CDN/1.0'
            ],
            'timeout' => 30,
            'sslverify' => true
        ];
        
        $response = wp_remote_request($url, $args);
        
        if (is_wp_error($response)) {
            return Result::error('Full purge request failed: ' . $response->get_error_message());
        }
        
        $statusCode = wp_remote_retrieve_response_code($response);
        $body = wp_remote_retrieve_body($response);
        $data = json_decode($body, true);
        
        if ($statusCode >= 200 && $statusCode < 300) {
            return Result::success('Full cache purge successful', $data ?: []);
        }
        
        $errorMessage = 'Full purge failed';
        if ($data && isset($data['msg'])) {
            $errorMessage = $data['msg'];
        }
        
        return Result::error($errorMessage, $statusCode, $data ?: []);
    }
    
    public function applyRecommendedSettings(): Result {
        // Fastly settings are managed via VCL or the dashboard
        // We don't modify service configuration programmatically
        return Result::success('Fastly settings are managed via VCL configuration in the Fastly dashboard');
    }
    
    public function testConnection(): Result {
        // Test by fetching service details
        $url = self::API_BASE . "/service/{$this->serviceId}";
        
        $args = [
            'method' => 'GET',
            'headers' => [
                'Fastly-Key' => $this->apiToken,
                'User-Agent' => 'Mamba-WooCommerce-CDN/1.0'
            ],
            'timeout' => 30,
            'sslverify' => true
        ];
        
        $response = wp_remote_request($url, $args);
        
        if (is_wp_error($response)) {
            return Result::error('Connection test failed: ' . $response->get_error_message());
        }
        
        $statusCode = wp_remote_retrieve_response_code($response);
        $body = wp_remote_retrieve_body($response);
        $data = json_decode($body, true);
        
        if ($statusCode >= 200 && $statusCode < 300) {
            $serviceName = $data['name'] ?? 'Unknown';
            return Result::success("Connected to Fastly service: {$serviceName}", $data ?: []);
        }
        
        $errorMessage = 'Connection failed';
        if ($data && isset($data['msg'])) {
            $errorMessage = $data['msg'];
        }
        
        return Result::error($errorMessage, $statusCode, $data ?: []);
    }
    
    /**
     * Check if Surrogate-Key headers should be sent
     */
    public function shouldSendSurrogateKeys(): bool {
        return $this->sendSurrogateKeys;
    }
    
    /**
     * Check if soft purge is enabled
     */
    public function isSoftPurgeEnabled(): bool {
        return $this->softPurge;
    }
}
