<?php

namespace apexl\Io;

use apexl\Config\ConfigurationInterface;
use apexl\Config\Exceptions\MissingConfigException;
use apexl\Io\includes\HookManager;
use apexl\Io\includes\RouteManager;
use apexl\Io\includes\System;
use apexl\Io\modules\system\services\MiddlewareCollector;
use apexl\Io\modules\system\services\ModuleManager;
use Exception;
use Slim\App;

final readonly class Client
{
    final public const string HOOK__BOOT = 'client.boot';

    protected System $system;

    /**
     * @throws Exception
     */
    public function __construct(
        public App $application,
        private ModuleManager $moduleManager,
        private RouteManager $routeManager,
        private HookManager $hookManager,
        private MiddlewareCollector $middlewareCollector,
        private ConfigurationInterface $config,
    ) {}

    /**
     * Bootstrap and run Io
     * UPDATED:: Now defaults to loading PHP files at the specified config directory. Passing anything other than __PHP__ here will result un an attempt to load the specific file, whatever the extension.
     * @throws Exception
     */
    public function start(): void
    {
        $this->bootstrap();
        $this->application->run();
    }

    /**
     * Bootstrap IO CMF
     * @throws Exception
     */
    public function bootstrap(): void
    {
        $this->setErrorOptions();
        $this->processModules();
        $this->addMiddleware();
        $this->routeManager->buildRoutes();

        // Attempt to initialise the System
        /** Add a boot hook so modules can set various defaults as soon as the start process is finished*/
        $this->hookManager->processHook(self::HOOK__BOOT);
    }

    /**
     * @throws MissingConfigException
     */
    private function setErrorOptions(): void
    {
        ini_set('display_errors', $this->config->get('error.display'));
        ini_set('display_startup_errors', $this->config->get('error.display'));
        error_reporting($this->config->get('error.reporting'));

    }

    public static function isCli(): bool
    {
        static $isCli;
        if (!isset($isCli)) {
            $isCli = php_sapi_name() === 'cli';
        }

        return $isCli;
    }

    /**
     * @throws Exception
     */
    private function processModules(): void
    {
        $this->moduleManager->init();
    }

    public function addMiddleware(): void
    {
        $weightedMiddlewares = $this->middlewareCollector->collect();

        foreach ($weightedMiddlewares as $middlewareCollection) {
            foreach ($middlewareCollection as $middleware) {
                $this->application->add($middleware);
            }
        }
    }
}
