<?php

declare(strict_types=1);


namespace ProRank\SEO\Services\Cdn;

use WP_Error;

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


/**
 * CDN Manager
 *
 * Minimal provider wrapper to test connection and purge caches.
 * Currently supports Cloudflare, BunnyCDN, Fastly, CloudFront, KeyCDN, and a generic webhook.
 */


class CdnManager {
    /**
     * Test connection to configured CDN provider
     *
     * @return array|WP_Error
     */
    public function test_connection(array $config = []) {
        $provider = $this->get_provider($config);

        if ($provider === 'cloudflare') {
            return $this->test_cloudflare($config);
        }

        if ($provider === 'bunnycdn') {
            return $this->test_bunny($config);
        }

        if ($provider === 'fastly') {
            return $this->test_fastly($config);
        }

        if ($provider === 'cloudfront') {
            return $this->test_cloudfront($config);
        }

        if ($provider === 'keycdn') {
            return $this->test_keycdn($config);
        }

        if ($provider === 'webhook') {
            return $this->test_webhook($config);
        }

        return new WP_Error('cdn_not_configured', __('No CDN configured', 'prorank-seo'));
    }

    /**
     * Purge everything
     *
     * @return true|WP_Error
     */
    public function purge_all() {
        $provider = $this->get_provider();

        if ($provider === 'cloudflare') {
            return $this->purge_cloudflare(true);
        }

        if ($provider === 'bunnycdn') {
            return $this->purge_bunny();
        }

        if ($provider === 'fastly') {
            return $this->purge_fastly(true);
        }

        if ($provider === 'cloudfront') {
            return $this->purge_cloudfront(true);
        }

        if ($provider === 'keycdn') {
            return $this->purge_keycdn(true);
        }

        if ($provider === 'webhook') {
            return $this->purge_webhook(true);
        }

        return new WP_Error('cdn_not_configured', __('No CDN configured', 'prorank-seo'));
    }

    /**
     * Purge URLs (best-effort; falls back to purge all if not supported)
     *
     * @param array $urls
     * @return true|WP_Error
     */
    public function purge_urls(array $urls) {
        $urls = array_values(array_filter(array_map('esc_url_raw', $urls)));
        if (empty($urls)) {
            return new WP_Error('invalid_urls', __('No valid URLs provided for purge.', 'prorank-seo'));
        }

        $provider = $this->get_provider();

        if ($provider === 'cloudflare') {
            return $this->purge_cloudflare(false, $urls);
        }

        if ($provider === 'bunnycdn') {
            // Bunny does not support URL purge on pull zones; purge all
            return $this->purge_bunny();
        }

        if ($provider === 'fastly') {
            return $this->purge_fastly(false, $urls);
        }

        if ($provider === 'cloudfront') {
            return $this->purge_cloudfront(false, $urls);
        }

        if ($provider === 'keycdn') {
            return $this->purge_keycdn(false, $urls);
        }

        if ($provider === 'webhook') {
            return $this->purge_webhook(false, $urls);
        }

        return new WP_Error('cdn_not_configured', __('No CDN configured', 'prorank-seo'));
    }

    /**
     * Get configured provider
     */
    private function get_provider(array $config = []): string {
        if (isset($config['cdn_provider'])) {
            return sanitize_key((string) $config['cdn_provider']);
        }

        return get_option('prorank_cdn_provider', 'none');
    }

    private function get_config_value(array $config, string $key, string $option_name): string {
        if (isset($config[$key])) {
            return (string) $config[$key];
        }

        return (string) get_option($option_name);
    }

    /**
     * Test Cloudflare credentials
     */
    private function test_cloudflare(array $config = []) {
        $zone_id = $this->get_config_value($config, 'cloudflare_zone_id', 'prorank_cloudflare_zone_id');
        $api_token = $this->get_config_value($config, 'cloudflare_api_token', 'prorank_cloudflare_api_token');

        if (!$zone_id || !$api_token) {
            return new WP_Error('cloudflare_not_configured', __('Cloudflare credentials not configured.', 'prorank-seo'));
        }

        $response = wp_remote_get(
            "https://api.cloudflare.com/client/v4/zones/{$zone_id}",
            [
                'headers' => [
                    'Authorization' => "Bearer {$api_token}",
                ],
                'timeout' => 10,
            ]
        );

        if (is_wp_error($response)) {
            return $response;
        }

        $body = json_decode(wp_remote_retrieve_body($response), true);
        if (empty($body['success'])) {
            return new WP_Error('cloudflare_api_error', __('Cloudflare API error', 'prorank-seo'));
        }

        return [
            'provider' => 'cloudflare',
            'status' => 'ok',
            'name' => $body['result']['name'] ?? '',
        ];
    }

    /**
     * Test BunnyCDN credentials
     */
    private function test_bunny(array $config = []) {
        $pullzone_id = $this->get_config_value($config, 'bunny_pullzone_id', 'prorank_bunny_pullzone_id');
        $api_key = $this->get_config_value($config, 'bunny_api_key', 'prorank_bunny_api_key');

        if (!$pullzone_id || !$api_key) {
            return new WP_Error('bunny_not_configured', __('BunnyCDN credentials not configured.', 'prorank-seo'));
        }

        $response = wp_remote_get(
            "https://api.bunny.net/pullzone/{$pullzone_id}",
            [
                'headers' => [
                    'AccessKey' => $api_key,
                ],
                'timeout' => 10,
            ]
        );

        if (is_wp_error($response)) {
            return $response;
        }

        if (wp_remote_retrieve_response_code($response) !== 200) {
            return new WP_Error('bunny_api_error', __('BunnyCDN API error', 'prorank-seo'));
        }

        return [
            'provider' => 'bunnycdn',
            'status' => 'ok',
        ];
    }

    /**
     * Test Fastly credentials
     */
    private function test_fastly(array $config = []) {
        $service_id = $this->get_config_value($config, 'fastly_service_id', 'prorank_fastly_service_id');
        $api_token = $this->get_config_value($config, 'fastly_api_token', 'prorank_fastly_api_token');

        if (!$service_id || !$api_token) {
            return new WP_Error('fastly_not_configured', __('Fastly credentials not configured.', 'prorank-seo'));
        }

        $response = wp_remote_get(
            "https://api.fastly.com/service/{$service_id}",
            [
                'headers' => [
                    'Fastly-Key' => $api_token,
                    'Accept' => 'application/json',
                ],
                'timeout' => 10,
            ]
        );

        if (is_wp_error($response)) {
            return $response;
        }

        if (wp_remote_retrieve_response_code($response) !== 200) {
            return new WP_Error('fastly_api_error', __('Fastly API error', 'prorank-seo'));
        }

        return [
            'provider' => 'fastly',
            'status' => 'ok',
        ];
    }

    /**
     * Test custom webhook
     */
    private function test_webhook(array $config = []) {
        $url = $this->get_config_value($config, 'cdn_webhook_url', 'prorank_cdn_webhook_url');
        if (!$url) {
            return new WP_Error('webhook_not_configured', __('Webhook URL not configured.', 'prorank-seo'));
        }
        // simple HEAD check
        $response = wp_remote_head($url, ['timeout' => 5]);
        if (is_wp_error($response)) {
            return $response;
        }
        return [
            'provider' => 'webhook',
            'status' => 'ok',
        ];
    }

    /**
     * Purge Cloudflare
     */
    private function purge_cloudflare(bool $purge_all = false, array $urls = []) {
        $zone_id = get_option('prorank_cloudflare_zone_id');
        $api_token = get_option('prorank_cloudflare_api_token');

        if (!$zone_id || !$api_token) {
            return new WP_Error('cloudflare_not_configured', __('Cloudflare credentials not configured.', 'prorank-seo'));
        }

        $payload = $purge_all ? ['purge_everything' => true] : ['files' => $urls];

        $response = wp_remote_post(
            "https://api.cloudflare.com/client/v4/zones/{$zone_id}/purge_cache",
            [
                'headers' => [
                    'Authorization' => "Bearer {$api_token}",
                    'Content-Type' => 'application/json',
                ],
                'body' => wp_json_encode($payload),
                'timeout' => 15,
            ]
        );

        if (is_wp_error($response)) {
            return $response;
        }

        $body = json_decode(wp_remote_retrieve_body($response), true);
        if (empty($body['success'])) {
            return new WP_Error('cloudflare_api_error', __('Cloudflare API error', 'prorank-seo'));
        }

        return true;
    }

    /**
     * Purge BunnyCDN (zone-wide)
     */
    private function purge_bunny() {
        $pullzone_id = get_option('prorank_bunny_pullzone_id');
        $api_key = get_option('prorank_bunny_api_key');

        if (!$pullzone_id || !$api_key) {
            return new WP_Error('bunny_not_configured', __('BunnyCDN credentials not configured.', 'prorank-seo'));
        }

        $response = wp_remote_post(
            "https://api.bunny.net/pullzone/{$pullzone_id}/purgeCache",
            [
                'headers' => [
                    'AccessKey' => $api_key,
                ],
                'timeout' => 15,
            ]
        );

        if (is_wp_error($response)) {
            return $response;
        }

        if (wp_remote_retrieve_response_code($response) !== 200) {
            return new WP_Error('bunny_api_error', __('BunnyCDN API error', 'prorank-seo'));
        }

        return true;
    }

    /**
     * Purge Fastly
     */
    private function purge_fastly(bool $purge_all = false, array $urls = []) {
        $service_id = get_option('prorank_fastly_service_id');
        $api_token = get_option('prorank_fastly_api_token');

        if (!$service_id || !$api_token) {
            return new WP_Error('fastly_not_configured', __('Fastly credentials not configured.', 'prorank-seo'));
        }

        if ($purge_all) {
            $endpoint = "https://api.fastly.com/service/{$service_id}/purge_all";
            $response = wp_remote_post(
                $endpoint,
                [
                    'headers' => [
                        'Fastly-Key' => $api_token,
                        'Accept' => 'application/json',
                    ],
                    'timeout' => 15,
                ]
            );
            if (is_wp_error($response)) {
                return $response;
            }
            if (wp_remote_retrieve_response_code($response) !== 200) {
                return new WP_Error('fastly_api_error', __('Fastly API error', 'prorank-seo'));
            }
            return true;
        }

        // Purge specific URLs
        foreach ($urls as $url) {
            $endpoint = 'https://api.fastly.com/purge/' . rawurlencode($url);
            $response = wp_remote_post(
                $endpoint,
                [
                    'headers' => [
                        'Fastly-Key' => $api_token,
                        'Accept' => 'application/json',
                    ],
                    'timeout' => 15,
                ]
            );
            if (is_wp_error($response)) {
                return $response;
            }
            if (wp_remote_retrieve_response_code($response) !== 200) {
                return new WP_Error('fastly_api_error', __('Fastly API error', 'prorank-seo'));
            }
        }

        return true;
    }

    /**
     * Purge via custom webhook
     */
    private function purge_webhook(bool $purge_all = false, array $urls = []) {
        $url = get_option('prorank_cdn_webhook_url');
        if (!$url) {
            return new WP_Error('webhook_not_configured', __('Webhook URL not configured.', 'prorank-seo'));
        }

        $payload = [
            'action' => $purge_all ? 'purge_all' : 'purge_urls',
            'urls'   => $purge_all ? [] : $urls,
        ];

        $response = wp_remote_post(
            $url,
            [
                'headers' => [
                    'Content-Type' => 'application/json',
                    'X-ProRank-Signature' => get_option('prorank_cdn_webhook_secret', ''),
                ],
                'body' => wp_json_encode($payload),
                'timeout' => 15,
            ]
        );

        if (is_wp_error($response)) {
            return $response;
        }

        $code = wp_remote_retrieve_response_code($response);
        if ($code < 200 || $code >= 300) {
            return new WP_Error('webhook_error', __('Webhook purge failed.', 'prorank-seo'));
        }

        return true;
    }

    /**
     * Test CloudFront credentials with a signed Distribution lookup.
     */
    private function test_cloudfront(array $config = []) {
        $distribution_id = $this->get_config_value($config, 'cloudfront_distribution_id', 'prorank_cloudfront_distribution_id');
        $access_key = $this->get_config_value($config, 'cloudfront_access_key', 'prorank_cloudfront_access_key');
        $secret_key = $this->get_config_value($config, 'cloudfront_secret_key', 'prorank_cloudfront_secret_key');

        if (!$distribution_id || !$access_key || !$secret_key) {
            return new WP_Error('cloudfront_not_configured', __('CloudFront credentials not configured.', 'prorank-seo'));
        }

        $region = $this->get_config_value($config, 'cloudfront_region', 'prorank_cloudfront_region') ?: 'us-east-1';
        $host = 'cloudfront.amazonaws.com';
        $amz_date = gmdate('Ymd\THis\Z');
        $date_stamp = gmdate('Ymd');
        $service = 'cloudfront';
        $request_method = 'GET';
        $canonical_uri = "/2020-05-31/distribution/{$distribution_id}";
        $canonical_querystring = '';
        $canonical_headers = "host:{$host}\nx-amz-date:{$amz_date}\n";
        $signed_headers = 'host;x-amz-date';
        $payload_hash = hash('sha256', '');
        $canonical_request = implode("\n", [
            $request_method,
            $canonical_uri,
            $canonical_querystring,
            $canonical_headers,
            $signed_headers,
            $payload_hash,
        ]);
        $algorithm = 'AWS4-HMAC-SHA256';
        $credential_scope = "{$date_stamp}/{$region}/{$service}/aws4_request";
        $string_to_sign = implode("\n", [
            $algorithm,
            $amz_date,
            $credential_scope,
            hash('sha256', $canonical_request),
        ]);
        $signing_key = $this->get_aws_signing_key($secret_key, $date_stamp, $region, $service);
        $signature = hash_hmac('sha256', $string_to_sign, $signing_key);
        $authorization = "{$algorithm} Credential={$access_key}/{$credential_scope}, SignedHeaders={$signed_headers}, Signature={$signature}";

        $response = wp_remote_get(
            "https://{$host}{$canonical_uri}",
            [
                'headers' => [
                    'X-Amz-Date' => $amz_date,
                    'Authorization' => $authorization,
                ],
                'timeout' => 15,
            ]
        );

        if (is_wp_error($response)) {
            return $response;
        }

        $code = wp_remote_retrieve_response_code($response);
        if ($code < 200 || $code >= 300) {
            return new WP_Error('cloudfront_api_error', __('CloudFront API error', 'prorank-seo'));
        }

        $domain_name = '';
        if (function_exists('simplexml_load_string')) {
            $previous = libxml_use_internal_errors(true);
            $xml = simplexml_load_string(wp_remote_retrieve_body($response));
            libxml_clear_errors();
            libxml_use_internal_errors($previous);
            if ($xml instanceof \SimpleXMLElement && isset($xml->DomainName)) {
                $domain_name = (string) $xml->DomainName;
            }
        }

        return [
            'provider' => 'cloudfront',
            'status' => 'ok',
            'distribution_id' => $distribution_id,
            'domain_name' => $domain_name,
        ];
    }

    /**
     * Purge CloudFront (creates invalidation)
     */
    private function purge_cloudfront(bool $purge_all = false, array $urls = []) {
        $distribution_id = get_option('prorank_cloudfront_distribution_id');
        $access_key = get_option('prorank_cloudfront_access_key');
        $secret_key = get_option('prorank_cloudfront_secret_key');

        if (!$distribution_id || !$access_key || !$secret_key) {
            return new WP_Error('cloudfront_not_configured', __('CloudFront credentials not configured.', 'prorank-seo'));
        }

        $paths = $purge_all ? ['/*'] : array_map(
            fn($u) => '/' . ltrim(wp_parse_url($u, PHP_URL_PATH) ?? '/', '/'),
            $urls
        );
        $paths = array_values(array_unique($paths));

        $body = [
            'Paths' => [
                'Quantity' => count($paths),
                'Items' => $paths,
            ],
            'CallerReference' => 'prorank-' . time(),
        ];

        // Use AWS REST API signed with Signature V4 (minimal)
        $region = get_option('prorank_cloudfront_region', 'us-east-1');
        $host = 'cloudfront.amazonaws.com';
        $amz_date = gmdate('Ymd\THis\Z');
        $date_stamp = gmdate('Ymd');
        $service = 'cloudfront';
        $request_method = 'POST';
        $canonical_uri = "/2020-05-31/distribution/{$distribution_id}/invalidation";
        $canonical_querystring = '';
        $canonical_headers = "content-type:application/json\nhost:{$host}\nx-amz-date:{$amz_date}\n";
        $signed_headers = 'content-type;host;x-amz-date';
        $payload_hash = hash('sha256', wp_json_encode($body));
        $canonical_request = implode("\n", [
            $request_method,
            $canonical_uri,
            $canonical_querystring,
            $canonical_headers,
            $signed_headers,
            $payload_hash,
        ]);
        $algorithm = 'AWS4-HMAC-SHA256';
        $credential_scope = "{$date_stamp}/{$region}/{$service}/aws4_request";
        $string_to_sign = implode("\n", [
            $algorithm,
            $amz_date,
            $credential_scope,
            hash('sha256', $canonical_request),
        ]);
        $signing_key = $this->get_aws_signing_key($secret_key, $date_stamp, $region, $service);
        $signature = hash_hmac('sha256', $string_to_sign, $signing_key);
        $authorization = "{$algorithm} Credential={$access_key}/{$credential_scope}, SignedHeaders={$signed_headers}, Signature={$signature}";

        $response = wp_remote_post(
            "https://{$host}{$canonical_uri}",
            [
                'headers' => [
                    'Content-Type' => 'application/json',
                    'X-Amz-Date' => $amz_date,
                    'Authorization' => $authorization,
                ],
                'body' => wp_json_encode($body),
                'timeout' => 20,
            ]
        );

        if (is_wp_error($response)) {
            return $response;
        }
        $code = wp_remote_retrieve_response_code($response);
        if ($code < 200 || $code >= 300) {
            return new WP_Error('cloudfront_api_error', __('CloudFront API error', 'prorank-seo'));
        }

        return true;
    }

    /**
     * Test KeyCDN credentials (zone check)
     */
    private function test_keycdn(array $config = []) {
        $zone_id = $this->get_config_value($config, 'keycdn_zone_id', 'prorank_keycdn_zone_id');
        $api_key = $this->get_config_value($config, 'keycdn_api_key', 'prorank_keycdn_api_key');

        if (!$zone_id || !$api_key) {
            return new WP_Error('keycdn_not_configured', __('KeyCDN credentials not configured.', 'prorank-seo'));
        }

        $response = wp_remote_get(
            "https://api.keycdn.com/zones.json?zones_id={$zone_id}",
            [
                'headers' => [
                    'Authorization' => 'Basic ' . base64_encode($api_key . ':'),
                ],
                'timeout' => 10,
            ]
        );

        if (is_wp_error($response)) {
            return $response;
        }

        if (wp_remote_retrieve_response_code($response) !== 200) {
            return new WP_Error('keycdn_api_error', __('KeyCDN API error', 'prorank-seo'));
        }

        return [
            'provider' => 'keycdn',
            'status' => 'ok',
        ];
    }

    /**
     * Purge KeyCDN
     */
    private function purge_keycdn(bool $purge_all = false, array $urls = []) {
        $zone_id = get_option('prorank_keycdn_zone_id');
        $api_key = get_option('prorank_keycdn_api_key');

        if (!$zone_id || !$api_key) {
            return new WP_Error('keycdn_not_configured', __('KeyCDN credentials not configured.', 'prorank-seo'));
        }

        if ($purge_all) {
            $endpoint = "https://api.keycdn.com/zones/purge/{$zone_id}.json";
            $response = wp_remote_post(
                $endpoint,
                [
                    'headers' => [
                        'Authorization' => 'Basic ' . base64_encode($api_key . ':'),
                    ],
                    'timeout' => 15,
                ]
            );
            if (is_wp_error($response)) {
                return $response;
            }
            if (wp_remote_retrieve_response_code($response) !== 200) {
                return new WP_Error('keycdn_api_error', __('KeyCDN API error', 'prorank-seo'));
            }
            return true;
        }

        // Purge URLs
        $endpoint = "https://api.keycdn.com/zones/purgeurl/{$zone_id}.json";
        $response = wp_remote_post(
            $endpoint,
            [
                'headers' => [
                    'Authorization' => 'Basic ' . base64_encode($api_key . ':'),
                    'Content-Type' => 'application/json',
                ],
                'body' => wp_json_encode(['urls' => array_values($urls)]),
                'timeout' => 15,
            ]
        );
        if (is_wp_error($response)) {
            return $response;
        }
        if (wp_remote_retrieve_response_code($response) !== 200) {
            return new WP_Error('keycdn_api_error', __('KeyCDN API error', 'prorank-seo'));
        }

        return true;
    }

    /**
     * Build AWS signing key
     */
    private function get_aws_signing_key(string $secret_key, string $date_stamp, string $region, string $service) {
        $kDate = hash_hmac('sha256', $date_stamp, 'AWS4' . $secret_key, true);
        $kRegion = hash_hmac('sha256', $region, $kDate, true);
        $kService = hash_hmac('sha256', $service, $kRegion, true);
        $kSigning = hash_hmac('sha256', 'aws4_request', $kService, true);
        return $kSigning;
    }
}
