<?php
/// file: app/Core/Request.php

declare(strict_types=1);

namespace App\Core;

final class Request
{
    public function __construct(
        private readonly string $method,
        private readonly string $uri,
        /** @var array<string, string> */
        private readonly array $params = []
    ) {
    }

    public static function fromGlobals(): self
    {
        $uri = $_SERVER['REQUEST_URI'] ?? '/';
        $q = strpos($uri, '?');
        if ($q !== false) {
            $uri = substr($uri, 0, $q);
        }
        $uri = rawurldecode($uri);
        if ($uri === '') {
            $uri = '/';
        }
        $method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
        return new self($method, $uri);
    }

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

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

    /** @return array<string, string> */
    public function params(): array
    {
        return $this->params;
    }

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

    public function input(string $key, ?string $default = null): ?string
    {
        $v = $_POST[$key] ?? $_GET[$key] ?? $default;
        if ($v === null) {
            return null;
        }
        return is_string($v) ? $v : (string) $v;
    }

    /** @return array<string, mixed> */
    public function allInput(): array
    {
        return array_merge($_GET, $_POST);
    }

    public function header(string $name): ?string
    {
        $key = 'HTTP_' . strtoupper(str_replace('-', '_', $name));
        $v = $_SERVER[$key] ?? null;
        return $v !== null ? (string) $v : null;
    }

    public function wantsJson(): bool
    {
        $accept = $this->header('Accept') ?? '';
        return str_contains($accept, 'application/json');
    }

    /** @return array<string, mixed>|null */
    public function jsonBody(): ?array
    {
        $raw = file_get_contents('php://input');
        if ($raw === false || $raw === '') {
            return null;
        }
        $data = json_decode($raw, true);
        return is_array($data) ? $data : null;
    }

    public function withParams(array $params): self
    {
        return new self($this->method, $this->uri, $params);
    }
}
