<?php

namespace Sitecake\Http;

/**
 * HTTP request wrapper — replaces Symfony\Component\HttpFoundation\Request.
 *
 * Exposes the subset of the Symfony HttpFoundation API actually used by SiteCake:
 *   $req->query->get/has/all            → $_GET
 *   $req->request->get/has/remove/all   → $_POST
 *   $req->files->get                    → $_FILES
 *   $req->isXmlHttpRequest()
 *   $req->getAcceptableContentTypes()
 *   $req->getMethod()
 *   $req->getSession()
 */
class Request
{
    public ParameterBag $query;
    public ParameterBag $request;
    public ParameterBag $files;
    public HeaderBag $headers;

    protected array $server;
    protected string $method;

    /** @var Session|null Lazily created */
    protected ?Session $session = null;

    public function __construct(
        array $query   = [],
        array $request = [],
        array $files   = [],
        array $server  = []
    ) {
        $this->query   = new ParameterBag($query);
        $this->request = new ParameterBag($request);
        $this->files   = new ParameterBag($files);
        $this->server  = $server;
        $this->method  = strtoupper($server['REQUEST_METHOD'] ?? 'GET');

        // Populate $headers from HTTP_* server variables, normalized to lowercase
        $headers = [];
        foreach ($server as $key => $value) {
            if (strpos($key, 'HTTP_') === 0) {
                $name = strtolower(str_replace('_', '-', substr($key, 5)));
                $headers[$name] = $value;
            }
        }
        $this->headers = new HeaderBag($headers);
    }

    /** Factory: populate from PHP superglobals. */
    public static function createFromGlobals(): self
    {
        return new self($_GET, $_POST, $_FILES, $_SERVER);
    }

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

    /**
     * Returns true when the request was made via XMLHttpRequest
     * (jQuery/fetch sends the X-Requested-With header).
     */
    public function isXmlHttpRequest(): bool
    {
        return isset($this->server['HTTP_X_REQUESTED_WITH'])
            && strtolower($this->server['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
    }

    /**
     * Parse the Accept header and return ordered MIME types.
     * @return string[]
     */
    public function getAcceptableContentTypes(): array
    {
        $header = $this->server['HTTP_ACCEPT'] ?? '';
        if ($header === '') {
            return [];
        }
        $types = [];
        foreach (explode(',', $header) as $part) {
            $types[] = trim(explode(';', $part)[0]);
        }
        return $types;
    }

    /** Lazily create and return the Session wrapper. */
    public function getSession(): Session
    {
        if ($this->session === null) {
            $this->session = new Session();
        }
        return $this->session;
    }

    /** Allow pre-injecting a Session instance (used by bootstrap session setup). */
    public function setSession(Session $session): void
    {
        $this->session = $session;
    }
}
