<?php
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedNamespaceFound
namespace SS\Core;

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

class Http
{
    const RETRIES = array(
        'license.validate' => 2,
        'visibility.score' => 1,
        'schema.build'     => 1,
        'qa.generate'      => 0,
    );

    /** Small debug logger (file + PHP error_log) */
    private static function dbg($msg){
        if (!defined('SS_TEL_DEBUG') || !SS_TEL_DEBUG) return;
        $line = '[SS_HTTP] ' . $msg;

        // File log
        if (defined('SS_TEL_DEBUG_FILE') && SS_TEL_DEBUG_FILE) {
            @file_put_contents(SS_TEL_DEBUG_FILE, $line . "\n", FILE_APPEND);
        }
    }

    public static function postJson($routeKey, $path, $payload = array(), $opts = array()){
        return self::request($routeKey, 'POST', $path, $payload, $opts);
    }

    public static function request($routeKey, $method, $path, $payload = array(), $opts = array()){
        $base   = (string) get_option(\SS_Settings::OPT_API_BASE, defined('SEARCHSHIFTER_API_BASE') ? SEARCHSHIFTER_API_BASE : '');
        $apiKey = (string) get_option(\SS_Settings::OPT_API_KEY, '');
        $domain = (string) get_option(
            \SS_Settings::OPT_DOMAIN,
            wp_parse_url( get_site_url(), PHP_URL_HOST )
        );


        $url = rtrim($base, '/') . '/' . ltrim($path, '/');

        $headers = array_filter(array(
            'Accept'        => 'application/json',
            'Content-Type'  => 'application/json',
            'User-Agent'    => 'SearchShifter/' . (defined('SEARCHSHIFTER_VERSION') ? SEARCHSHIFTER_VERSION : 'unknown'),
            'X-Api-Key'     => $apiKey ?: null,
            'Authorization' => $apiKey ? ('Bearer ' . $apiKey) : null,
            'X-Domain'      => $domain ?: null,
            'X-SS-Domain'   => $domain ?: null,
            'X-SS-Client'   => 'wordpress',
        ));

        $args = array(
            'timeout' => isset($opts['timeout']) ? (int)$opts['timeout'] : 12,
            'headers' => $headers,
            'method'  => $method,
            'body'    => $method === 'GET' ? null : wp_json_encode($payload),
        );

        $maxRetries = isset(self::RETRIES[$routeKey]) ? self::RETRIES[$routeKey] : 0;
        $attempts   = 0;
        $start      = microtime(true);

        while (true) {
            $attempts++;
            self::dbg(sprintf('-> %s %s attempt=%d route=%s body=%s', $method, $url, $attempts, $routeKey, substr(json_encode($payload),0,200)));

            $resp = wp_remote_request($url, $args);

            if (is_wp_error($resp)) {
                $lastErr = $resp->get_error_message();
                self::dbg('!! transport error: ' . $lastErr);
                if ($attempts <= $maxRetries) {
                    self::telemetryRetry($routeKey, $attempts);
                    self::sleepWithJitter($attempts);
                    continue;
                }
                self::telemetryError($routeKey, 0, $attempts, $start);
                return array('ok' => false, 'status' => 0, 'error' => $lastErr);
            }

            $code = (int) wp_remote_retrieve_response_code($resp);
            $body = wp_remote_retrieve_body($resp);
            self::dbg(sprintf('<- code=%d body[0..200]=%s', $code, substr((string)$body, 0, 200)));

            // Retry only on 5xx
            if ($code >= 500 && $code <= 599) {
                if ($attempts <= $maxRetries) {
                    self::telemetryRetry($routeKey, $attempts);
                    self::sleepWithJitter($attempts);
                    continue;
                }
                self::telemetryError($routeKey, $code, $attempts, $start);
                return array('ok' => false, 'status' => $code, 'error' => 'Server error');
            }

            // 2xx → success
            if ($code >= 200 && $code < 300) {
                $json = json_decode($body, true);
                return array('ok' => true, 'status' => $code, 'json' => $json, 'raw' => $body);
            }

            // 4xx → no retry
            self::telemetryError($routeKey, $code, $attempts, $start);
            $msg = 'Request failed';
            if ($body && is_string($body)) {
                $decoded = json_decode($body, true);
                if (is_array($decoded) && !empty($decoded['message'])) $msg = $decoded['message'];
            }
            return array('ok' => false, 'status' => $code, 'error' => $msg);
        }
    }

    private static function sleepWithJitter($attempt){
        $map   = array(1 => 750, 2 => 1500, 3 => 3000);
        $base  = isset($map[$attempt]) ? $map[$attempt] : 3000;
        $jitter = (int) round($base * (0.8 + (wp_rand(0, 40) / 100)));
        usleep($jitter * 1000);
    }

    private static function telemetryRetry($routeKey, $attempt){
        if (class_exists('SS\\Core\\Telemetry')) {
            Telemetry::queue('retry', array('endpoint' => $routeKey, 'retry_count' => (int)$attempt));
            self::dbg(sprintf('queued retry route=%s attempt=%d', $routeKey, $attempt));
        }
    }

    private static function telemetryError($routeKey, $status, $attempts, $start){
        if (class_exists('SS\\Core\\Telemetry')) {
            Telemetry::queue('api_error', array(
                'endpoint'    => $routeKey,
                'http_status' => (int)$status,
                'retry_count' => max(0, (int)$attempts - 1),
                'duration_ms' => (int) round((microtime(true) - $start) * 1000),
            ));
            self::dbg(sprintf('queued api_error route=%s status=%d attempts=%d', $routeKey, $status, $attempts));
        }
    }
}
