<?php
namespace Skeleton;

use GuzzleHttp\Psr7\Response;
use Helpers\Log\LogSysteme;
use Helpers\Trad\Trad;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Container\ContainerInterface;

class Application
{

    public $modules = [];

    private $container;

    /**
     *
     * @param array $modules
     */
    public function __construct(ContainerInterface $container, array $modules = [])
    {
        $this->container = $container;
        foreach ($modules as $module) {
                $this->container->get($module);
        }
    }

    public function run(ServerRequestInterface $request)
    {
        $uri = $request->getUri()->getPath();
        
        if (! empty($uri) && substr($uri, - 1) === '/') {
            return (new Response())->withStatus(301)->withHeader('Location', substr($uri, 0, - 1));
        }

        $response = new Response();

        $route = $this->container->get(Router::class)->match($request);
        
        if (\is_null($route) && substr($uri, - 4) !== '.png' && substr($uri, - 4) !== '.jpg' && substr($uri, - 5) !== '.jpeg') {
            return (new Response())->withStatus(301)->withHeader('Location', $this->container->get(Router::class)->generateUri('Index.Index.error'));
        }

        // DEBUG : Uncaught Error: Call to a member function getParams() on null in ...
        if ($route === null) {
            LogSysteme::prefixErrorLog('Invalid route for request '.$request->getUri()->__toString());
        }
        
        $params = $route->getParams();
        $request = array_reduce(array_keys($params), function ($request, $key) use ($params) {
            return $request->withAttribute($key, $params[$key]);
        }, $request);

        /**
         * Prise en compte des param Get pour la gestion des Rules Modules/Controller/action
         */
        $this->container->set(\Psr\Http\Message\ServerRequestInterface::class, $request);

        $callback = $route->getCallback();
        
        if (\is_string($callback)) {
            $callback = $this->container->get($callback);
        }
        
        $response = call_user_func_array($callback, [
            $request
        ]);
        
        
        if (\is_string($response) || is_bool($response)) {
            return new Response(200, [], (string) $response);
        } elseif ($response instanceof ResponseInterface) {
            return $response;
        } else {
            throw new \Exception('La reponse est pas une chaine de caractere ou une instance de ResponseInterface pour la route "'. ($route !== null ? $route->getName() : '').'"');
        }
        return $response;
    }
    
    /**
     * builderIndex
     *
     * @param  mixed $builder
     * @param  string $pathDir
     * @param  array<mixed> $modulesGlobal
     * @param  array<mixed> $moduleSpecifique
     * @param  array<mixed> $moduleExterne
     * @return array<mixed>
     */
    public static function builderIndex(&$builder, string $pathDir, array $modulesGlobal = [], array $moduleSpecifique = [], array $moduleExterne = []) : array
    {

        if (isset($_SESSION['environnement']) && $_SESSION['environnement'] =='production') {
            $builder->enableCompilation($_SESSION['dir_tmp'].'cachePHPDI'.$_SESSION['cache']);
        }
        $builder->addDefinitions($pathDir);

        /**
         * Recuperation des Modules Standart
         */
        foreach ($modulesGlobal as $module) {
            if ($module::DEFINITIONS) {
                $builder->addDefinitions($module::DEFINITIONS);
            }
        }

        /**
         * Recuperation des Modules externes
         */
        foreach ($moduleExterne as $module) {
            if ($module::DEFINITIONS) {
                $builder->addDefinitions($module::DEFINITIONS);
            }
        }

        /**
         * Recuperation des Modules Specifiques
         */
        if (isset($moduleSpecifique[$_SESSION['Session_NumClient'] ?? 0]) && $moduleSpecifique[$_SESSION['Session_NumClient'] ?? 0]::DEFINITIONS) {
            $builder->addDefinitions($moduleSpecifique[$_SESSION['Session_NumClient'] ?? 0]::DEFINITIONS);
        }

        if (isset($moduleSpecifique[$_SESSION['Session_NumClient'] ?? 0])) {
            $moduleSpecifiqueForMerge = array();
            $moduleSpecifiqueForMerge = [$moduleSpecifique[$_SESSION['Session_NumClient'] ?? 0]];
        } else {
            $moduleSpecifiqueForMerge = array();
        }

        return array_merge($modulesGlobal, $moduleSpecifiqueForMerge);
    }

    public static function getAppRoot() :string
    {
        $s = realpath(__DIR__.'/../..');
        if (!is_string($s)) {
            throw new \Exception('Invalid path');
        }
        return $s;
    }
}
