<?php
/**
 * Application Bootstrap
 *
 * Initialise DB, settings, auth, modules, i18n, thème.
 * Utilisable en deux modes :
 *   1. Routeur : appelé depuis index.php (point d'entrée unique)
 *   2. Legacy  : require depuis une page PHP directe (backward compat)
 */

// Errors go to log, not output (production-safe)
ini_set('display_errors', '0');
ini_set('log_errors', '1');

// Resolve root path (mon-appli/../ = project root)
define('ROOT_PATH', dirname(__DIR__));

// Load configuration
require_once ROOT_PATH . '/lib/Config.php';

// Ensure log directory exists
if (!is_dir(LOG_PATH)) {
    mkdir(LOG_PATH, 0750, true);
}

// Autoload libraries from /lib
spl_autoload_register(function (string $class): void {
    $file = LIB_PATH . '/' . $class . '.php';
    if (file_exists($file)) {
        require_once $file;
    }
});

// Initialize database (also seeds initial data) — ne dépend pas de la session.
$db = Database::getInstance();

// Load application settings (may override compile-time constants)
$settings = Settings::getInstance();

// Start session — la durée configurée doit être appliquée AVANT session_start()
// (d'où le chargement des settings en amont). Régler les params de session une
// fois la session active émet des warnings et reste sans effet.
$cfgSessionLifetime = (int)$settings->get('session_lifetime', SESSION_LIFETIME);
Session::start($cfgSessionLifetime);

// Apply debug/trace from DB settings
$logger = Logger::getInstance();
$logger->setDebugMode((bool)$settings->get('debug_mode', DEBUG_MODE));
$logger->setTraceMode((bool)$settings->get('trace_mode', TRACE_MODE));

// Log request
$logger->trace("Request", [
    'method' => $_SERVER['REQUEST_METHOD'] ?? '',
    'uri'    => $_SERVER['REQUEST_URI']    ?? '',
]);

// Initialize authentication
$auth = new Auth();
$currentUser = $auth->getCurrentUser();

// Discover and register modules from mon-appli/modules/*/module.php
$moduleRegistry = Module::getInstance();
$_moduleAutoloadPaths = [];
foreach (glob(WEBROOT_PATH . '/modules/*/module.php') ?: [] as $moduleFile) {
    $descriptor = require $moduleFile;
    if (is_array($descriptor)) {
        $moduleRegistry->register($descriptor);
        if (!empty($descriptor['autoload_path'])) {
            $_moduleAutoloadPaths[] = $descriptor['autoload_path'];
        }
    }
}
// Autoload module classes : Modules\Oracle\Controllers\X → modules/oracle/controllers/X.php
if (!empty($_moduleAutoloadPaths)) {
    spl_autoload_register(function (string $class) use ($_moduleAutoloadPaths): void {
        $parts = explode('\\', $class);
        if (count($parts) < 3 || $parts[0] !== 'Modules') return;
        $relPath = implode('/', array_slice($parts, 2)) . '.php';
        foreach ($_moduleAutoloadPaths as $base) {
            $file = $base . '/' . $relPath;
            if (file_exists($file)) { require_once $file; return; }
        }
    });
}

// Migrate module configs from DB to securite/modules/*.json (idempotent)
$moduleRegistry->migrateConfigsFromDb();

// Initialize i18n
$i18n = I18n::getInstance();
$userLang = $currentUser['language'] ?? null;
$i18n->init($userLang);
// Store resolved language in session
Session::set('language', $i18n->getLanguage());

// Determine active theme
$appDefaultTheme = $settings->get('default_theme', DEFAULT_THEME);
if ($currentUser) {
    $activeTheme = $currentUser['theme'] ?: $appDefaultTheme;
} else {
    $activeTheme = $appDefaultTheme;
}

// Handle language switch via GET parameter ?lang=xx
if (!empty($_GET['lang']) && in_array($_GET['lang'], LANGUAGES)) {
    $newLang = $_GET['lang'];
    $i18n->setLanguage($newLang);
    Session::set('language', $newLang);
    if ($currentUser) {
        (new User())->update($currentUser['id'], ['language' => $newLang]);
    }
    // Redirect to same page without ?lang= to avoid resubmission
    $redirect = strtok($_SERVER['REQUEST_URI'], '?');
    header("Location: $redirect");
    exit;
}

// Handle theme switch via GET parameter ?theme=xx
if (!empty($_GET['theme']) && in_array($_GET['theme'], THEMES)) {
    $newTheme = $_GET['theme'];
    Session::set('theme', $newTheme);
    if ($currentUser) {
        (new User())->update($currentUser['id'], ['theme' => $newTheme]);
    }
    $redirect = strtok($_SERVER['REQUEST_URI'], '?');
    header("Location: $redirect");
    exit;
}

// Allow session-level theme override (for guests)
if (Session::has('theme') && in_array(Session::get('theme'), THEMES)) {
    $activeTheme = Session::get('theme');
}

// ── Mode maintenance ──────────────────────────────────────────────────────
// Pendant une mise à jour (admin/update.php), l'app passe en maintenance :
// 503 pour tout le monde SAUF les app_admin (qui gardent l'accès pour piloter
// la MAJ et récupérer si elle échoue). La page de login reste accessible aux
// visiteurs non connectés pour qu'un admin puisse s'authentifier et reprendre
// la main. Le flag vit dans securite/database.sqlite (préservé par la MAJ).
if ((bool)$settings->get('maintenance_mode', false)) {
    $isLogin   = str_contains($_SERVER['REQUEST_URI'] ?? '', 'login');
    $adminPass = $currentUser && $auth->hasRole(ROLE_APP_ADMIN);
    if (!$adminPass && !$isLogin) {
        http_response_code(503);
        include WEBROOT_PATH . '/includes/503.php';
        exit;
    }
}
