<?php

declare(strict_types=1);

namespace App\Framework\HttpClient;

final readonly class ClientOptions
{
    public function __construct(
        public int $timeout = 10,
        public int $connectTimeout = 3,
        public bool $followRedirects = true,
        public int $maxRedirects = 5,
        public bool $verifySsl = true,
        public array $query = [],
        public ?string $userAgent = null,
        public ?string $proxy = null,
        public ?AuthConfig $auth = null,
        public array $curlOptions = [], // Für zusätzliche cURL-Optionen
        public bool $throwOnError = true, // Soll bei 4xx/5xx Exceptions geworfen werden?
        public array $allowedStatusCodes = [], // Erlaubte Status-Codes (wenn nicht leer)
    ) {
    }

    /**
     * Erstellt neue Optionen mit geänderten Werten
     */
    public function with(array $options): self
    {
        return new self(
            timeout: $options['timeout'] ?? $this->timeout,
            connectTimeout: $options['connectTimeout'] ?? $this->connectTimeout,
            followRedirects: $options['followRedirects'] ?? $this->followRedirects,
            maxRedirects: $options['maxRedirects'] ?? $this->maxRedirects,
            verifySsl: $options['verifySsl'] ?? $this->verifySsl,
            query: $options['query'] ?? $this->query,
            userAgent: $options['userAgent'] ?? $this->userAgent,
            proxy: $options['proxy'] ?? $this->proxy,
            auth: $options['auth'] ?? $this->auth,
            curlOptions: $options['curlOptions'] ?? $this->curlOptions,
            throwOnError: $options['throwOnError'] ?? $this->throwOnError,
            allowedStatusCodes: $options['allowedStatusCodes'] ?? $this->allowedStatusCodes,
        );
    }

    /**
     * Factory-Methoden für häufige Konfigurationen
     */
    public static function withTimeout(int $timeout): self
    {
        return new self(timeout: $timeout);
    }

    public static function withAuth(AuthConfig $auth): self
    {
        return new self(auth: $auth);
    }

    public static function withProxy(string $proxy): self
    {
        return new self(proxy: $proxy);
    }

    public static function insecure(): self
    {
        return new self(verifySsl: false);
    }

    public static function withoutRedirects(): self
    {
        return new self(followRedirects: false);
    }

    public static function withQuery(array $query): self
    {
        return new self(query: $query);
    }

    public static function withUserAgent(string $userAgent): self
    {
        return new self(userAgent: $userAgent);
    }

    /**
     * Kombiniert diese Optionen mit anderen
     */
    public function merge(ClientOptions $other): self
    {
        return new self(
            timeout: $other->timeout !== 10 ? $other->timeout : $this->timeout,
            connectTimeout: $other->connectTimeout !== 3 ? $other->connectTimeout : $this->connectTimeout,
            followRedirects: $other->followRedirects !== true ? $other->followRedirects : $this->followRedirects,
            maxRedirects: $other->maxRedirects !== 5 ? $other->maxRedirects : $this->maxRedirects,
            verifySsl: $other->verifySsl !== true ? $other->verifySsl : $this->verifySsl,
            query: array_merge($this->query, $other->query),
            userAgent: $other->userAgent ?? $this->userAgent,
            proxy: $other->proxy ?? $this->proxy,
            auth: $other->auth ?? $this->auth,
            curlOptions: array_merge($this->curlOptions, $other->curlOptions),
            throwOnError: $other->throwOnError !== true ? $other->throwOnError : $this->throwOnError,
            allowedStatusCodes: ! empty($other->allowedStatusCodes) ? $other->allowedStatusCodes : $this->allowedStatusCodes,
        );
    }
}
