<?php

declare(strict_types=1);

namespace Tests\Support;

/**
 * Lightweight cURL-based HTTP Client for Auth Service Integration Tests.
 * No Guzzle required — uses PHP's built-in cURL extension (confirmed present).
 */
class HttpClient
{
    private string $baseUrl;
    private int    $timeout;

    public function __construct(?string $baseUrl = null, int $timeout = 15)
    {
        $this->baseUrl = rtrim(
            $baseUrl ?? ($_ENV['AUTH_BASE_URL'] ?? 'http://localhost/projects/SMS-MICROSERVICES/auth-service/public'),
            '/'
        );
        $this->timeout = $timeout;
    }

    public function post(string $path, array $body = [], array $extraHeaders = []): HttpResponse
    {
        return $this->send('POST', $path, $body, $extraHeaders);
    }

    public function get(string $path, array $extraHeaders = []): HttpResponse
    {
        return $this->send('GET', $path, [], $extraHeaders);
    }

    /** Convenience: build a Bearer Authorization header pair */
    public function bearerHeader(string $token): array
    {
        return ["Authorization: Bearer {$token}"];
    }

    // ─── Internal ─────────────────────────────────────────────────────────────

    private function send(string $method, string $path, array $body, array $extraHeaders): HttpResponse
    {
        $url = $this->baseUrl . '/' . ltrim($path, '/');

        $headers = array_merge(
            ['Content-Type: application/json', 'Accept: application/json'],
            $extraHeaders
        );

        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HEADER         => true,
            CURLOPT_TIMEOUT        => $this->timeout,
            CURLOPT_HTTPHEADER     => $headers,
            CURLOPT_CUSTOMREQUEST  => $method,
        ]);

        if ($method === 'POST' && !empty($body)) {
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
        }

        $raw        = curl_exec($ch);
        $statusCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $headerSize = (int) curl_getinfo($ch, CURLINFO_HEADER_SIZE);
        $curlError  = curl_error($ch);
        curl_close($ch);

        if ($curlError) {
            throw new \RuntimeException("cURL failed [{$method} {$url}]: {$curlError}");
        }

        $rawBody = substr($raw, $headerSize);
        $decoded = json_decode($rawBody, true);

        return new HttpResponse($statusCode, $decoded ?? [], $rawBody);
    }
}

/**
 * Immutable HTTP response value object.
 */
class HttpResponse
{
    public function __construct(
        public readonly int    $status,
        public readonly array  $data,
        public readonly string $rawBody
    ) {}

    public function get(string $key, mixed $default = null): mixed
    {
        return $this->data[$key] ?? $default;
    }

    /** Drill into nested keys using dot notation: "user.id" */
    public function dot(string $path, mixed $default = null): mixed
    {
        $keys  = explode('.', $path);
        $value = $this->data;
        foreach ($keys as $key) {
            if (!is_array($value) || !array_key_exists($key, $value)) {
                return $default;
            }
            $value = $value[$key];
        }
        return $value;
    }

    public function isSuccess(): bool    { return $this->status >= 200 && $this->status < 300; }
    public function isCreated(): bool    { return $this->status === 201; }
    public function isOk(): bool         { return $this->status === 200; }
    public function isBadRequest(): bool { return $this->status === 400; }
    public function isUnauth(): bool     { return $this->status === 401; }
    public function isForbidden(): bool  { return $this->status === 403; }
    public function isConflict(): bool   { return $this->status === 409; }
    public function isServerError(): bool{ return $this->status >= 500; }

    public function dump(): string
    {
        return "HTTP {$this->status} | " . $this->rawBody;
    }
}
