<?php

declare(strict_types=1);

namespace App\Framework\Http;

use App\Framework\Core\InterfaceImplementationLocator;
use App\Framework\DI\Container;
use App\Framework\Discovery\Results\DiscoveryResults;
use App\Framework\Http\HttpMiddleware;
use App\Framework\Http\Middlewares\ControllerRequestMiddleware;
use App\Framework\Http\Middlewares\RoutingMiddleware;
use App\Framework\Validation\ValidationErrorMiddleware;

/**
 * Verwaltet die HTTP-Middleware-Pipeline
 */
final readonly class MiddlewareManager
{
    /**
     * @var array<string> Array mit Middleware-Klassen
     */
    #private array $middlewares = [];

    public HttpMiddlewareChain $chain;

    public function __construct(
        private Container        $container,
        private DiscoveryResults $discoveryResults,
    )
    {
        // Standard-Middlewares registrieren
        /*$this->middlewares = [
            ControllerRequestMiddleware::class,
            ValidationErrorMiddleware::class,
            RoutingMiddleware::class
        ];*/

        $middlewares = $this->buildMiddlewareStack();

        foreach($middlewares as $middleware) {
            #echo $middleware . " " . $this->getMiddlewarePriority($middleware) . "<br>". PHP_EOL;
        }


        $this->chain = new HttpMiddlewareChain(
            $middlewares,
            fn() => new HttpResponse(Status::NOT_FOUND),
            $this->container
        );
    }

    private function buildMiddlewareStack(): array
    {
        $middlewares = $this->discoveryResults->get(HttpMiddleware::class);
        $middlewares = array_column($middlewares, 'class');
        return $this->sortMiddlewaresByPriority($middlewares);
    }

    /**
     * Erstellt eine Middleware-Chain mit den registrierten Middlewares
     */
    /*public function createMiddlewareChain(callable $fallbackHandler): HttpMiddlewareChain
    {
        return new HttpMiddlewareChain(
            $this->middlewares,
            $fallbackHandler,
            $this->container
        );
    }*/

    public static function getPriority(object|string $middlewareClass): int
    {
        $reflection = new \ReflectionClass($middlewareClass);
        $attrs = $reflection->getAttributes(MiddlewarePriorityAttribute::class);
        if ($attrs) {
            /** @var MiddlewarePriorityAttribute $attr */
            $attr = $attrs[0]->newInstance();
            if ($attr->offset !== 0) {
                return $attr->priority->value + $attr->offset;
            }
            return $attr->priority->value;
        }
        // Standard-Priorität (oder Fehlermeldung)
        return MiddlewarePriority::BUSINESS_LOGIC->value;
    }

    // Methode zum Sortieren der Middleware nach Priorität
    private function sortMiddlewaresByPriority($middlewares): array
    {
        usort($middlewares, function (object|string $a, object|string $b) {
            $priorityA = $this->getMiddlewarePriority($a);
            $priorityB = $this->getMiddlewarePriority($b);

            return $priorityB <=> $priorityA; // Höhere Priorität zuerst
        });

        return $middlewares;
    }

    // Hilfsmethode zum Abrufen der Middleware-Priorität
    private function getMiddlewarePriority(object|string $middlewareClass): int
    {
        $priority = $this->discoveryResults->get(MiddlewarePriorityAttribute::class);
        $middlewareClass = ltrim($middlewareClass, '\\');

        foreach($priority as $item) {
            #dd($middlewareClass);
            if ($item['class'] === $middlewareClass) {
                #debug($item['attribute_data']['priority']);
                #dd($item['attribute_data']['priority']->value);
                $priority = $item['attribute_data']['priority'];
                if(!is_int($priority)) {
                    $priority = $priority->value;
                }

                return $priority + ($item['attribute_data']['offset'] ?? 0);
            }
        }

        // Middleware has no Priority: Set to default
        return MiddlewarePriority::BUSINESS_LOGIC->value;
    }
}
