<?php

declare(strict_types=1);

namespace Plugin\tnt_mcp\src\Facade;

use JsonException;

/**
 * What came back from an outbound HTTP call (design §4.4, §4.7): scalars and a string body.
 *
 * Deliberately NOT a PSR-7 response or a cURL handle — a snippet gets the answer, not the transport.
 * `truncated` is part of the answer on purpose: a snippet that reads a capped body must be able to
 * tell "the endpoint said this" from "the endpoint said more than we were willing to read".
 */
final class HttpResult implements \JsonSerializable
{
    /**
     * @param array<string,string> $headers response headers, names lower-cased; repeated names
     *                                      joined with ", " as RFC 9110 allows
     * @param string               $url     the URL the response actually came from — after redirects
     */
    public function __construct(
        public readonly int $status,
        public readonly array $headers,
        public readonly string $body,
        public readonly bool $truncated,
        public readonly string $url,
    ) {
    }

    /** 2xx. Anything else is the endpoint saying no, which is not this facade's business to retry. */
    public function ok(): bool
    {
        return $this->status >= 200 && $this->status < 300;
    }

    /**
     * The body decoded as JSON, or `null` when it is not JSON — most webhook endpoints answer with
     * JSON, and a snippet should not have to reach for a decoder that the sandbox may not allow.
     */
    public function json(): mixed
    {
        try {
            return \json_decode($this->body, true, 32, \JSON_THROW_ON_ERROR);
        } catch (JsonException) {
            return null;
        }
    }

    public function header(string $name): ?string
    {
        return $this->headers[\strtolower(\trim($name))] ?? null;
    }

    /**
     * @return array{
     *     status: int,
     *     ok: bool,
     *     headers: array<string,string>,
     *     body: string,
     *     truncated: bool,
     *     url: string
     * }
     */
    public function jsonSerialize(): array
    {
        return [
            'status'    => $this->status,
            'ok'        => $this->ok(),
            'headers'   => $this->headers,
            'body'      => $this->body,
            'truncated' => $this->truncated,
            'url'       => $this->url,
        ];
    }
}
