<?php
declare(strict_types=1);

namespace App\Core;

final class Request
{
    private string $method;
    private string $path;
    private array $params = [];

    public function __construct()
    {
        $this->method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
        if ($this->method === 'POST') {
            $override = $_POST['_method'] ?? $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] ?? null;
            if (is_string($override) && in_array(strtoupper($override), ['PUT', 'PATCH', 'DELETE'], true)) {
                $this->method = strtoupper($override);
            }
        }
        $uri = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?: '/';
        $base = rtrim((string) config('app.base_path', ''), '/');
        if ($base !== '' && str_starts_with($uri, $base)) {
            $uri = substr($uri, strlen($base)) ?: '/';
        }
        $this->path = '/' . trim($uri, '/');
        if ($this->path !== '/') {
            $this->path = rtrim($this->path, '/') ?: '/';
        }
    }

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

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

    public function setParams(array $params): void
    {
        $this->params = $params;
    }

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

    public function input(string $key, mixed $default = null): mixed
    {
        $src = $this->method === 'GET' ? $_GET : $_POST;
        if (array_key_exists($key, $src)) {
            return is_string($src[$key]) ? trim($src[$key]) : $src[$key];
        }
        if (array_key_exists($key, $_GET)) {
            return is_string($_GET[$key]) ? trim($_GET[$key]) : $_GET[$key];
        }
        return $default;
    }

    public function all(): array
    {
        $data = array_merge($_GET, $_POST);
        unset($data['_csrf'], $data['_method']);
        return array_map(static function ($v) {
            return is_string($v) ? trim($v) : $v;
        }, $data);
    }

    public function int(string $key, int $default = 0): int
    {
        return (int) $this->input($key, $default);
    }

    public function query(string $key, mixed $default = null): mixed
    {
        return isset($_GET[$key]) && is_string($_GET[$key]) ? trim($_GET[$key]) : $default;
    }
}
