<?php

declare(strict_types=1);

namespace apexl\Io\modules\system\hooks;

use apexl\Io\interfaces\AbstractHook;
use apexl\Io\middleware\addCorsHeaders;
use apexl\Io\middleware\AddRouteToHttpPaths;
use apexl\Io\modules\system\collections\MiddlewareCollectionCollection;
use apexl\Io\modules\system\services\MiddlewareCollector;
use apexl\Io\modules\system\services\WhoopsHandlerCollector;
use app\vendor\apexl\io\src\Io\middleware\AddBuildHeader;
use app\vendor\apexl\io\src\Io\middleware\InjectIoRequest;
use Slim\App;
use Slim\Middleware\BodyParsingMiddleware;
use Slim\Middleware\MethodOverrideMiddleware;
use Slim\Middleware\RoutingMiddleware;
use Zeuxisoo\Whoops\Slim\WhoopsMiddleware;

final readonly class AddMiddleware implements AbstractHook
{
    public function __construct(
        private App $application,
        private WhoopsHandlerCollector $whoopsHandlerCollector,
    ) {}

    public function hooks(): array
    {
        return [MiddlewareCollector::HOOK__COLLECT];
    }

    public function __invoke(MiddlewareCollectionCollection $weightedMiddleware): MiddlewareCollectionCollection
    {
        $routingMiddleware = new RoutingMiddleware(
            $this->application->getRouteResolver(),
            $this->application->getRouteCollector()->getRouteParser()
        );

        $weightedMiddleware->add(addCorsHeaders::class, weight: MiddlewareCollector::WEIGHT__FIRST);
        $weightedMiddleware->add(BodyParsingMiddleware::class, weight: MiddlewareCollector::WEIGHT__FIRST);
        $weightedMiddleware->add(
            $this->whoopsMiddleware(),
            weight: MiddlewareCollector::WEIGHT__FIRST
        );
        $weightedMiddleware->add(MethodOverrideMiddleware::class, weight: MiddlewareCollector::WEIGHT__FIRST);
        $weightedMiddleware->add($routingMiddleware, weight: MiddlewareCollector::WEIGHT__FIRST);
        $weightedMiddleware->add(InjectIoRequest::class, weight: MiddlewareCollector::WEIGHT__FIRST);
        $weightedMiddleware->add(AddRouteToHttpPaths::class, weight: MiddlewareCollector::WEIGHT__FIRST);

        $weightedMiddleware->add(AddBuildHeader::class, weight: MiddlewareCollector::WEIGHT__LAST);

        return $weightedMiddleware;
    }

    private function whoopsMiddleware(): WhoopsMiddleware
    {
        $handlers = $this->whoopsHandlerCollector->collect();

        return new WhoopsMiddleware(handlers: $handlers);
    }
}
