<?php

// Strenge Typprüfung für Parameter- und Rückgabetypen aktivieren.
declare(strict_types=1);

/**
 * Front-Controller der Webanwendung.
 *
 * Aufgaben:
 * - Startet die Session und initialisiert den Autoloader für den App-Namespace.
 * - Lädt die zentrale Konfiguration aus config/config.php.
 * - Instanziiert die Hauptcontroller (Auth, Dashboard, User-Management).
 * - Steuert das Routing anhand des GET-Parameters "route".
 * - Leitet View-Result-Arrays an das zentrale Layout (renderLayout) weiter
 *   oder führt Redirects aus.
 *
 * WICHTIG:
 * - Diese Datei ist der einzige öffentliche Einstiegspunkt (Entry Point) der App.
 * - Alle neuen Routen sollten über den Switch-Block am Ende ergänzt werden.
 */

// Eine neue Session wird gestartet und die entsprechende Variable ($_SESSION) angelegt
// oder eine bestehende wird fortgesetzt.
session_start();

// PHP-Fehler erfassen, aber veraltete Hinweise (E_DEPRECATED) ignorieren,
// weil sie sonst im Zusammenspiel mit IIS/fastcgi zu 500-Fehlern führen können.
error_reporting(E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);
ini_set('display_errors', '0');

/*
 * Registriert eine Autoload-Funktion für Klassen mit dem Namespace-Präfix "App\".
 * Statt jede Klasse manuell über "require pfad_zur_klasse.php" einzubinden,
 * versucht PHP nun automatisch, die passende Datei zu laden, sobald eine Klasse
 * im Namespace "App\..." verwendet wird.
 */
spl_autoload_register(
    static function (string $class): void {
        $prefix  = 'App\\';
        $baseDir = __DIR__ . '/../app/';

        $len = strlen($prefix);
        if (strncmp($prefix, $class, $len) !== 0) {
            return;
        }

        $relativeClass = substr($class, $len);
        $file          = $baseDir . str_replace('\\', DIRECTORY_SEPARATOR, $relativeClass) . '.php';

        if (file_exists($file) === true) {
            require $file;
        }
    }
);

// Layout-Funktion einbinden (renderLayout)
require __DIR__ . '/views/layout.php';

// Die Konfigurationsdatei liefert ein assoziatives Array mit den Teilbereichen
// "ldap", "snmp", "security" und "logging" (u. a. Session-Keys, Timeout-Einstellungen, OIDs, Log-Pfade).
$configPath = __DIR__ . '/../config/config.php';
if (file_exists($configPath) === false) {
    // Fail fast: ohne Konfiguration macht die App keinen Sinn
    http_response_code(500);
    echo 'Konfigurationsdatei config/config.php wurde nicht gefunden. '
        . 'Bitte config.example.php kopieren und anpassen.';
    exit;
}

/** @var array<string, mixed> $config */
$config = require $configPath;

use App\Controllers\AuthController;
use App\Controllers\DashboardController;
use App\Controllers\UserManagementController;
use App\Services\Logging\LoggingService;

// Globalen Logger initialisieren, damit auch Fehler außerhalb der Controller
// (z. B. in index.php selbst) sauber protokolliert werden.
$globalLogger = new LoggingService($config['logging'] ?? []);

/**
 * Globale Fehlerbehandlung:
 * - PHP-Fehler (Warnings, Notices, ...) werden in den Logger geschrieben.
 * - Unbehandelte Exceptions werden ebenfalls geloggt und führen zu einer generischen 500er-Meldung.
 */
set_error_handler(
    static function (
        int $severity,
        string $message,
        string $file = '',
        int $line = 0
    ) use ($globalLogger): bool {
        // Fehler nur loggen, wenn sie durch error_reporting() nicht unterdrückt sind.
        if ((error_reporting() & $severity) === 0) {
            return false;
        }

        $globalLogger->log(
            'error',
            'PHP-Fehler: ' . $message,
            [
                'severity' => $severity,
                'file'     => $file,
                'line'     => $line,
            ]
        );

        // false zurückgeben = PHP darf seinen Standard-Handler zusätzlich verwenden
        // (der Browser sieht wegen display_errors=0 trotzdem nichts).
        return false;
    }
);

set_exception_handler(
    static function (\Throwable $exception) use ($globalLogger): void {
        $globalLogger->logException(
            'Unbehandelte Exception in der Anwendung.',
            $exception,
            [
                'request_uri' => $_SERVER['REQUEST_URI'] ?? null,
                'route'       => $_GET['route'] ?? null,
            ]
        );

        http_response_code(500);
        echo 'Es ist ein unerwarteter Fehler aufgetreten. '
            . 'Bitte versuchen Sie es später erneut oder wenden Sie sich an den Administrator.';
    }
);

/**
 * Hilfsfunktion: Prüft, ob ein Benutzer eingeloggt ist.
 * Wenn nicht, wird auf die Login-Seite umgeleitet.
 *
 * @param array<string, mixed> $config
 */
function requireLogin(array $config): void
{
    // session_key_user aus dem Config-Array lesen. Wenn nicht gesetzt oder null, Standard "admin_user" verwenden.
    $sessionKey = $config['security']['session_key_user'] ?? 'admin_user';

    // Prüfen, ob in $_SESSION unter diesem Key ein eingeloggter Benutzer hinterlegt ist.
    // Falls nicht, zurück zur Login-Seite umleiten.
    if (isset($_SESSION[$sessionKey]) === false) {
        header('Location: index.php?route=login');
        exit;
    }
}

/**
 * Verarbeitet ein View-Result oder Redirect-Result.
 *
 * @param array<string, mixed>|null $result
 */
function handleResult(?array $result): void
{
    if ($result === null) {
        return;
    }

    // Redirect-Result
    if (isset($result['redirect']) === true) {
        header('Location: ' . (string)$result['redirect']);
        exit;
    }

    // View-Result
    $contentView = (string)($result['view'] ?? '');
    $viewData    = (array)($result['data'] ?? []);

    // Standard: Wir gehen davon aus, dass es KEINE Loginseite ist,
    // außer der Controller sagt explizit etwas anderes.
    if (array_key_exists('loginPage', $viewData) === false) {
        $viewData['loginPage'] = false;
    }

    $pageTitle  = (string)($result['pageTitle'] ?? '');
    $activeMenu = $result['activeMenu'] ?? null;

    if ($contentView === '' || file_exists($contentView) === false) {
        http_response_code(500);
        echo 'Interner Fehler: Content-View wurde nicht gefunden.';
        exit;
    }

    // Hier rufen wir jetzt die Layout-Funktion aus layout.php auf
    renderLayout(
        $contentView,
        $viewData,
        $pageTitle,
        is_string($activeMenu) ? $activeMenu : null
    );
}

// Zentrale Controller der Anwendung initialisieren und ihnen die vollständige Konfiguration übergeben.
// Die Controller holen sich daraus bei Bedarf ihre spezifischen Teilkonfigurationen (z. B. "ldap" oder "snmp").
// Jeder Controller erzeugt intern seinen eigenen LoggingService aus $config['logging'].
$authController          = new AuthController($config);
$dashboardController     = new DashboardController($config);
$userManagementController = new UserManagementController($config);

// Route aus dem Query-Parameter lesen. Standardroute ist "login",
// sodass nicht angemeldete Benutzer automatisch auf die Login-Seite geführt werden.
$route = $_GET['route'] ?? 'login';

// Einfache Router-Logik: Jede Route ruft eine Controller-Methode auf und
// übergibt deren View-Result an handleResult(). Neue Seiten werden hier ergänzt.
switch ($route) {
    case 'login':
        // Login-Formular anzeigen (ggf. mit Fehlermeldung)
        $result = $authController->showLoginForm();
        handleResult($result);
        break;

    case 'login.submit':
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            // Falscher HTTP-Verb: einfach zurück zum Login
            header('Location: index.php?route=login');
            exit;
        }
        $result = $authController->processLogin();
        handleResult($result);
        break;

    case 'logout':
        $result = $authController->logout();
        handleResult($result);
        break;

    case 'dashboard':
        requireLogin($config);
        $result = $dashboardController->show();
        handleResult($result);
        break;

    case 'users':
        requireLogin($config);
        $result = $userManagementController->show();
        handleResult($result);
        break;

    default:
        http_response_code(404);
        echo 'Route nicht gefunden.';
        break;
}
