<?php

declare(strict_types=1);

namespace Numinix\SeekmodoWordPress\Sdk;

use GuzzleHttp\Psr7\Response;
use Psr\Http\Client\ClientExceptionInterface;
use Psr\Http\Client\ClientInterface as PsrHttpClient;
use Psr\Http\Client\NetworkExceptionInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use RuntimeException;

/**
 * PSR-18 HTTP client backed by WordPress's `wp_remote_request` so
 * the connector doesn't have to ship Guzzle (bloats the plugin
 * download and risks conflicting with other plugins that bundle
 * their own Guzzle).
 *
 * Honours the HTTP API filter ecosystem (`pre_http_request`,
 * `http_request_args`, `http_response`) — operators can intercept
 * connector traffic the same way they intercept any other plugin's
 * outbound HTTP, useful for staging-environment routing or
 * deep-debugging.
 *
 * Network-level failures (`WP_Error`) are mapped to a PSR-18
 * {@see NetworkExceptionInterface}, which the SDK's
 * {@see \Numinix\SeekmodoSdk\Client} translates into a
 * `ClientException::KIND_NETWORK` so the connector's fallback path
 * triggers correctly.
 */
final class WpHttpClient implements PsrHttpClient
{
    private float $timeoutSeconds;

    public function __construct(float $timeoutSeconds = 2.0)
    {
        $this->timeoutSeconds = $timeoutSeconds;
    }

    public function sendRequest(RequestInterface $request): ResponseInterface
    {
        if (!function_exists('wp_remote_request')) {
            throw new class('wp_remote_request not available') extends RuntimeException implements ClientExceptionInterface {};
        }

        $headers = [];
        foreach ($request->getHeaders() as $name => $values) {
            $headers[$name] = implode(', ', $values);
        }

        $args = [
            'method' => $request->getMethod(),
            'headers' => $headers,
            'timeout' => $this->timeoutSeconds,
            'redirection' => 0,
            'sslverify' => true,
            'blocking' => true,
        ];
        $body = (string) $request->getBody();
        if ($body !== '') {
            $args['body'] = $body;
        }

        $response = wp_remote_request((string) $request->getUri(), $args);

        if (\is_wp_error($response)) {
            $err = $response->get_error_message();
            // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- message escaped; $request is the PSR-7 object, not output
            throw new class('Seekmodo HTTP failure: ' . esc_html($err), $request) extends RuntimeException implements NetworkExceptionInterface {
                private RequestInterface $req;
                public function __construct(string $message, RequestInterface $req)
                {
                    parent::__construct($message);
                    $this->req = $req;
                }
                public function getRequest(): RequestInterface
                {
                    return $this->req;
                }
            };
        }

        $status = (int) wp_remote_retrieve_response_code($response);
        $responseHeaders = (array) wp_remote_retrieve_headers($response);
        $responseBody = (string) wp_remote_retrieve_body($response);

        return new Response($status, $responseHeaders, $responseBody);
    }
}
