<?php

declare(strict_types=1);

namespace App\Framework\Http;

use App\Framework\DI\Initializer;
use App\Framework\Http\Cookies\Cookie;
use App\Framework\Http\Cookies\Cookies;
use App\Framework\Router\Exception\RouteNotFound;

/**
 * Erstellt HTTP-Requests aus den globalen Variablen
 */
final readonly class RequestFactory
{
    public function __construct(
        private RequestIdGenerator $requestIdGenerator
    ) {}

    /**
     * Erstellt einen HTTP-Request aus den globalen Variablen
     */
    #[Initializer]
    public function createFromGlobals(): Request
    {
        $server = new ServerEnvironment($_SERVER);

        $originalRequestUri = (string)$server->getRequestUri();
        $rawPath = parse_url($originalRequestUri, PHP_URL_PATH);

        if ($rawPath === false) {
            throw new RouteNotFound($originalRequestUri);
        }

        if($rawPath !== '/') {
            $rawPath = rtrim($rawPath, '/');
        }

        $headers = $this->getHeadersFromServer();
        $cookies = $this->getCookiesFromServer();
        $method = $server->getRequestMethod();
        $body = file_get_contents('php://input') ?: '';

        $parsedBody = new RequestBody($method, $headers, $body, $_POST);

        if ($method === Method::POST) {
            $_method = Method::tryFrom($parsedBody->get('_method', ''));
            if($_method !== null) {
                $method = $_method;
            }
        }


        return new HttpRequest(
            method: $method,
            headers: $headers,
            body: $body,
            path: $rawPath,
            queryParams: $_GET,
            files: new UploadedFiles($_FILES),
            cookies: $cookies,
            server: $server,
            id: $this->requestIdGenerator->generate(),
            parsedBody: $parsedBody
        );
    }

    /**
     * Extrahiert HTTP-Header aus den Server-Variablen
     */
    private function getHeadersFromServer(): Headers
    {
        $headers = new Headers();

        foreach ($_SERVER as $key => $value) {
            // Prüfen auf HTTP_-Präfix (Standard-Header)
            if (str_starts_with($key, 'HTTP_')) {
                $headerName = str_replace('_', '-', substr($key, 5));
                $headers = $headers->with($headerName, $value);
            }
            // Spezielle Header wie Content-Type und Content-Length haben kein HTTP_-Präfix
            elseif (in_array($key, ['CONTENT_TYPE', 'CONTENT_LENGTH'])) {
                $headerName = str_replace('_', '-', $key);
                $headers = $headers->with($headerName, $value);
            }
        }

        return $headers;
    }

    private function getCookiesFromServer(): Cookies
    {
        $cookies = [];

        foreach ($_COOKIE as $key => $value) {
            $cookies[] = new Cookie($key, $value);
        }

        return new Cookies(...$cookies);
    }
}
