<?php

use Picea\Picea;
use function DI\autowire, DI\create, DI\get;

use Lean\{ Lean, Routing, Event\RoutingCompileRoutes, Event\RoutingMapRoutes };
use Mcnd\Event;
use Taxus\Taxus;
use Storage\Session;
use Notes\Route\Attribute\Method\Route;
use Notes\Security\SecurityHandler;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\{ ResponseInterface, ServerRequestInterface };

return [
    Event\EventManager::class => autowire(Event\EventManager::class),

    Event\EventMiddleware::class => function($c) {
        $mw = new Event\EventMiddleware($c, $c->get(Event\EventManager::class));
        $mw->fromAttributes($c->get(Notes\Event\EventFetcher::class));
        $mw->fromDefinition($c->get(Event\EventDefinition::class));

        return $mw;
    },

    Event\EventDefinition::class => function($c) {
        return new Event\EventDefinition([

            new class($c->has(\Picea\Extension\UrlExtension::class) ? $c->get(\Picea\Extension\UrlExtension::class) : null) implements RoutingCompileRoutes {
                public function __construct(
                    protected ? \Picea\Extension\UrlExtension $extension,
                ) {}

                public function execute(Routing $routing, Route $attribute) : void
                {
                    if (null !== ($name = $attribute->name ?? null)) {
                        $this->extension->registerRoute($name, $attribute->getRoute(), $attribute->class, $attribute->classMethod, $attribute->methods ?? (array)$attribute->method);
                    }
                }
            },

            new class() implements RoutingMapRoutes {
                public function execute(Routing $routing, ContainerInterface $container, ServerRequestInterface & $request, Route $attribute) : void
                {
                    $class = $attribute->class;
                    $method = $attribute->classMethod;
                    $object = $container->get($class);

                    $request = $request->withAttribute('lean.route', $attribute);

                    # Checking if user needs to be logged
                    if ( $container->has(SecurityHandler::class) ){
                        $securityHandler = $container->get(SecurityHandler::class);

                        if ( $redirect = $securityHandler->verify($class, $method) ) {
                            if ( empty($object->user) || ! $object->user->logged ) {
                                $routing->session->set('redirectedFrom', (string) $request->getUri());
                                $routing->response = $redirect;

                                return;
                            }
                        }

                        if ( $securityHandler->isLocked($class, $method) && $container->has(Taxus::class) ) {
                            if ( $forbidden = $container->get(SecurityHandler::class)->taxus($class, $method, $object->user ?? null) ) {
                                $routing->response = $forbidden;

                                return;
                            }
                        }
                    }

                    if ($container->has(Picea::class)) {
                        $container->get(Picea::class)->globalVariables['route'] = $attribute;
                    }

                    if ($container->has(Session::class)) {
                        $container->get(Session::class)->set("lean.route", $attribute);
                    }
                }
            },
        ]);
    },

    Notes\Event\EventFetcher::class => function($c) {
        $fetcher = new Notes\Event\EventFetcher(null, null, $c->get('events.caching'));

        $fetcher->setFolderList(array_map(function($item) {
            return $item;
        }, $c->get(Lean::class)->getEvents()));

        return $fetcher;
    },
];