<?php

namespace App;

use App\Controller\BaseController;
use App\Controller\FrontController;
use App\Router\Request\HttpRequest;
use App\Router\Middleware\IHttpMiddleware;
use App\Router\Request\IRequest;
use App\Router\Route;
use App\Views\Directives\Navigate;
use Shared\Attributes\Route as RouteAttribute;
use App\Router\Router;
use App\Router\Session;
use Shared\Log;

class App
{
    private string $appName;
    private int $version;

    private ?IHttpMiddleware $middlewarePipeline = null;

    private Container $container;

    private Router $router;

    private array $controllers = [];

    private FrontController $frontController;

    public function __construct(string $appName, int $version, \App\Container $diContainer)
    {
        $this->appName = $appName;
        $this->version = $version;
        $this->container = $diContainer;
        $this->router = new Router("");
        $this->frontController = new FrontController($this->router,$this->container);
    }

    public function use(IHttpMiddleware $middleware)
    {
        if ($this->middlewarePipeline === null) {
            $this->middlewarePipeline = $middleware;
        } else {
            // Chain the new middleware to the end of the existing pipeline
            $currentMiddleware = $this->middlewarePipeline;
            while ($currentMiddleware->getNext() !== null) {
                $currentMiddleware = $currentMiddleware->getNext();
            }
            $currentMiddleware->setNext($middleware);
        }
    }

    public function getAppName(): string
    {
        return $this->appName;
    }

/*    public function twigConfigure(array $extensionClassNames = []): void
    {
        if (!$this->container->has(\Twig\Environment::class)) {
            throw new \LogicException('You cannot use the "twigConfigure" method if the Twig Bundle is not available. Try running "composer require twig/twig".');
        }

        $twigEnvironment = $this->container->get(\Twig\Environment::class);

        if (empty($extensionClassNames)) {
            $twigEnvironment->addExtension(new Navigate($this->router));

        } else {
            foreach ($extensionClassNames as $extensionClassName) {
                if (class_exists($extensionClassName)) {
                    $extensionInstance = new $extensionClassName();
                    if ($extensionInstance instanceof \Twig\Extension\ExtensionInterface) {
                        $twigEnvironment->addExtension($extensionInstance);
                    } else {
                        throw new \InvalidArgumentException("Class '$extensionClassName' does not implement Twig\Extension\ExtensionInterface.");
                    }
                } else {
                    throw new \InvalidArgumentException("Class '$extensionClassName' does not exist.");
                }
            }
        }
    }*/



    public function getVersion(): int
    {
        return $this->version;
    }

    public function run(IRequest $request)
    {
        if ($this->middlewarePipeline == null) {
            return $this->frontController->dispatch($request);
        }
        // Exécutez le middleware en utilisant le pipeline
        return $this->middlewarePipeline->handle($request, function($request) {
            // Logique de gestion principale de la requête ici
            $this->frontController->dispatch($request);
        });

    }

    /**
     * @throws \ReflectionException
     */
    public function mapControllers(): void
    {
        $classes = $this->container->getAllRegisteredClassNames();

        foreach ($classes as $class) {
            if ($this->isController($class)) {
                $this->mapControllerRoutes($class);
            }
        }
    }
    /**
     * @throws \ReflectionException
     */
    function mapControllerRoutes(string $controllerClass): void
    {
        $reflectionClass = new \ReflectionClass($controllerClass);
        $attributes = $reflectionClass->getAttributes(RouteAttribute::class);
        $prefix = '';
        if (!empty($attributes)) {

            $prefix = $attributes[0]->newInstance()->getPath();
        }

        foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {

            foreach ($method->getAttributes(RouteAttribute::class) as $attribute) {

                /** @var RouteAttribute $route */
                $route = $attribute->newInstance();

                $this->router->addControllerRoute(
                    implode('|', $route->getMethods()),
                    $prefix . $route->getPath(),
                    $controllerClass,
                    $method->getName(),
                    $route->getName()
                );
            }
        }
    }


    function isController(string $class): bool
    {
        $reflectionClass = new \ReflectionClass($class);
        return $reflectionClass->isSubclassOf(BaseController::class);
    }
}

