<?php

namespace App\Core;

class Request
{
    private array $attributes = [];
    private ?array $json = null;

    public function __construct(
        private array $server,
        private string $rawBody
    ) {
    }

    public static function capture(): self
    {
        return new self($_SERVER, file_get_contents('php://input') ?: '');
    }

    public function method(): string
    {
        return strtoupper($this->server['REQUEST_METHOD'] ?? 'GET');
    }

    public function path(): string
    {
        $path = parse_url($this->server['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?: '/';
        $scriptDir = rtrim(str_replace('\\', '/', dirname($this->server['SCRIPT_NAME'] ?? '')), '/');

        if ($scriptDir !== '' && $scriptDir !== '/' && str_starts_with($path, $scriptDir)) {
            $path = substr($path, strlen($scriptDir));
        }

        $path = '/' . ltrim($path, '/');
        return rtrim($path, '/') ?: '/';
    }

    public function json(): array
    {
        if ($this->json !== null) {
            return $this->json;
        }

        if (trim($this->rawBody) === '') {
            return $this->json = [];
        }

        $decoded = json_decode($this->rawBody, true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            throw new \App\Exceptions\ValidationException('Invalid JSON: ' . json_last_error_msg());
        }

        return $this->json = ($decoded ?: []);
    }

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

    public function header(string $name): ?string
    {
        $key = 'HTTP_' . strtoupper(str_replace('-', '_', $name));
        if (isset($this->server[$key])) {
            return $this->server[$key];
        }

        if (strtolower($name) === 'authorization' && isset($this->server['REDIRECT_HTTP_AUTHORIZATION'])) {
            return $this->server['REDIRECT_HTTP_AUTHORIZATION'];
        }

        return null;
    }

    public function bearerToken(): ?string
    {
        $header = $this->header('Authorization');
        if (!$header || !str_starts_with($header, 'Bearer ')) {
            return null;
        }

        return trim(substr($header, 7));
    }

    public function ip(): string
    {
        return $this->server['REMOTE_ADDR'] ?? '127.0.0.1';
    }

    public function setAttribute(string $key, mixed $value): void
    {
        $this->attributes[$key] = $value;
    }

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