<?php

declare(strict_types=1);

namespace SHServ\Integrations\GAuth\Http;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;

final class Psr7Response implements ResponseInterface
{
    private string $protocolVersion = '1.1';
    private int $statusCode = 200;
    private string $reasonPhrase = '';
    private array $headers = [];
    private StreamInterface $body;

    public function __construct(int $statusCode = 200, array $headers = [], ?StreamInterface $body = null, string $reasonPhrase = '')
    {
        $this->statusCode = $statusCode;
        $this->headers = $this->normalizeHeaders($headers);
        $this->body = $body ?? new Psr7Stream('');
        $this->reasonPhrase = $reasonPhrase;
    }

    private function normalizeHeaders(array $headers): array
    {
        $normalized = [];
        foreach ($headers as $name => $values) {
            $name = strtolower($name);
            if (!is_array($values)) {
                $values = [$values];
            }
            $normalized[$name] = array_map('strval', $values);
        }
        return $normalized;
    }

    public function getProtocolVersion(): string
    {
        return $this->protocolVersion;
    }

    public function withProtocolVersion(string $version): ResponseInterface
    {
        $new = clone $this;
        $new->protocolVersion = $version;
        return $new;
    }

    public function getHeaders(): array
    {
        $result = [];
        foreach ($this->headers as $name => $values) {
            $result[$this->studlyCase($name)] = $values;
        }
        return $result;
    }

    public function hasHeader(string $name): bool
    {
        return isset($this->headers[strtolower($name)]);
    }

    public function getHeader(string $name): array
    {
        return $this->headers[strtolower($name)] ?? [];
    }

    public function getHeaderLine(string $name): string
    {
        return implode(', ', $this->getHeader($name));
    }

    public function withHeader(string $name, $value): ResponseInterface
    {
        $new = clone $this;
        $new->headers[strtolower($name)] = is_array($value) ? array_map('strval', $value) : [(string) $value];
        return $new;
    }

    public function withAddedHeader(string $name, $value): ResponseInterface
    {
        $new = clone $this;
        $name = strtolower($name);
        if (!isset($new->headers[$name])) {
            $new->headers[$name] = [];
        }
        $new->headers[$name] = array_merge($new->headers[$name], is_array($value) ? array_map('strval', $value) : [(string) $value]);
        return $new;
    }

    public function withoutHeader(string $name): ResponseInterface
    {
        $new = clone $this;
        unset($new->headers[strtolower($name)]);
        return $new;
    }

    public function getBody(): StreamInterface
    {
        return $this->body;
    }

    public function withBody(StreamInterface $body): ResponseInterface
    {
        $new = clone $this;
        $new->body = $body;
        return $new;
    }

    public function getStatusCode(): int
    {
        return $this->statusCode;
    }

    public function withStatus(int $code, string $reasonPhrase = ''): ResponseInterface
    {
        $new = clone $this;
        $new->statusCode = $code;
        $new->reasonPhrase = $reasonPhrase;
        return $new;
    }

    public function getReasonPhrase(): string
    {
        return $this->reasonPhrase;
    }

    private function studlyCase(string $name): string
    {
        return str_replace(' ', '-', ucwords(str_replace('-', ' ', $name)));
    }
}
