<?php

declare(strict_types=1);

namespace App\Core;

use Throwable;

class Application
{
    private Router $router;

    public function __construct()
    {
        $this->loadConfiguration();
        $this->configureApplication();
        $this->startSession();
        $this->connectDatabase();

        $this->router = new Router();
    }

    private function loadConfiguration(): void
    {
        Config::set(
            'app',
            require CONFIG_PATH . '/app.php'
        );

        Config::set(
            'database',
            require CONFIG_PATH . '/database.php'
        );

        Config::set(
            'mail',
            require CONFIG_PATH . '/mail.php'
        );
    }

    private function configureApplication(): void
    {
        date_default_timezone_set(
            (string) config(
                'app.timezone',
                'Africa/Johannesburg'
            )
        );

        $debug = (bool) config(
            'app.debug',
            false
        );

        ini_set(
            'display_errors',
            $debug ? '1' : '0'
        );

        error_reporting(E_ALL);

        set_exception_handler(
            function (Throwable $exception) use ($debug): void {
                http_response_code(500);

                if ($debug) {
                    echo '<pre style="padding:20px;">';
                    echo e($exception->__toString());
                    echo '</pre>';
                    return;
                }

                echo 'A system error occurred.';
            }
        );
    }

    private function startSession(): void
    {
        if (session_status() === PHP_SESSION_ACTIVE) {
            return;
        }

        session_name(
            (string) config(
                'app.session.name',
                'linkage_conference_session'
            )
        );

        session_set_cookie_params([
            'lifetime' => (int) config(
                'app.session.lifetime',
                7200
            ),
            'path' => '/',
            'secure' => (bool) config(
                'app.session.secure',
                true
            ),
            'httponly' => true,
            'samesite' => (string) config(
                'app.session.same_site',
                'Lax'
            ),
        ]);

        ini_set('session.use_strict_mode', '1');
        ini_set('session.use_only_cookies', '1');

        session_start();
    }

    private function connectDatabase(): void
    {
        Database::connect(
            (array) config('database')
        );
    }

    public function router(): Router
    {
        return $this->router;
    }

    public function run(): void
    {
        $this->router->dispatch(
            Request::method(),
            Request::uri()
        );
    }
}