<?php

declare(strict_types=1);

namespace App\Framework\Database\Middleware;

final class MiddlewarePipeline
{
    /** @var QueryMiddleware[] */
    private array $middleware = [];

    public function add(QueryMiddleware $middleware): self
    {
        $this->middleware[] = $middleware;

        return $this;
    }

    public function addMultiple(array $middleware): self
    {
        foreach ($middleware as $m) {
            $this->add($m);
        }

        return $this;
    }

    public function process(QueryContext $context, callable $finalHandler): mixed
    {
        // Sortiere Middleware nach Priorität (höchste zuerst)
        $sortedMiddleware = $this->middleware;
        usort($sortedMiddleware, fn ($a, $b) => $b->getPriority() <=> $a->getPriority());

        // Baue die Pipeline von hinten nach vorne auf
        $pipeline = $finalHandler;

        for ($i = count($sortedMiddleware) - 1; $i >= 0; $i--) {
            $middleware = $sortedMiddleware[$i];
            $pipeline = fn (QueryContext $ctx) => $middleware->process($ctx, $pipeline);
        }

        return $pipeline($context);
    }

    public function getMiddleware(): array
    {
        return $this->middleware;
    }

    public function hasMiddleware(string $className): bool
    {
        foreach ($this->middleware as $middleware) {
            if ($middleware instanceof $className) {
                return true;
            }
        }

        return false;
    }

    public function getMiddlewareByType(string $className): ?QueryMiddleware
    {
        foreach ($this->middleware as $middleware) {
            if ($middleware instanceof $className) {
                return $middleware;
            }
        }

        return null;
    }
}
