<?php

declare(strict_types=1);

class Session {
    public static function start(): void {
        if (session_status() === PHP_SESSION_NONE) {
            // Configuration d'un répertoire de sessions dédié et persistant
            $sessionPath = __DIR__ . '/../../sessions';
            if (!is_dir($sessionPath)) {
                mkdir($sessionPath, 0700, true);
            }
            ini_set('session.save_path', $sessionPath);

            // Configuration des sessions adaptée pour les applications mobiles
            ini_set('session.use_strict_mode', '1');
            ini_set('session.cookie_httponly', '1');

            // Permettre les connexions non-HTTPS en développement
            $isProduction = (getenv('APP_ENV') === 'production');
            ini_set('session.cookie_secure', $isProduction ? '1' : '0');

            // SameSite None pour permettre les requêtes cross-origin (applications mobiles)
            ini_set('session.cookie_samesite', 'None');

            // Configuration de la durée de vie des sessions : 24 heures
            $sessionLifetime = 86400; // 24 heures
            ini_set('session.gc_maxlifetime', (string)$sessionLifetime);
            ini_set('session.cookie_lifetime', (string)$sessionLifetime);

            // Configuration du garbage collector pour qu'il ne supprime pas trop tôt
            // gc_probability / gc_divisor = probabilité d'exécution (1/100 = 1%)
            ini_set('session.gc_probability', '1');
            ini_set('session.gc_divisor', '100');

            // Récupérer le session_id du Bearer token si présent
            self::getSessionFromBearer();

            session_start();

            // Log détaillé après le démarrage de la session (DEBUG)
            $logFile = __DIR__ . '/../../logs/session_' . date('Y-m-d') . '.log';
            $sessionId = session_id();
            $sessionExists = isset($_SESSION) && !empty($_SESSION);
            $sessionData = $sessionExists ? json_encode($_SESSION) : 'empty';
            $sessionFile = $sessionPath . '/sess_' . $sessionId;
            $sessionFileExists = file_exists($sessionFile);

            $logMessage = date('Y-m-d H:i:s') . " - Session started\n";
            $logMessage .= "  Session ID: $sessionId\n";
            $logMessage .= "  Session path: $sessionPath\n";
            $logMessage .= "  Session file exists: " . ($sessionFileExists ? 'YES' : 'NO') . "\n";
            $logMessage .= "  Session data exists: " . ($sessionExists ? 'YES' : 'NO') . "\n";
            $logMessage .= "  Session data: $sessionData\n";

            file_put_contents($logFile, $logMessage, FILE_APPEND);
        }
    }

    public static function login(array $userData): void {
        $_SESSION['user_id'] = $userData['id'];
        $_SESSION['user_email'] = $userData['email'] ?? '';
        $_SESSION['entity_id'] = $userData['fk_entite'] ?? null;
        $_SESSION['fk_role'] = $userData['fk_role'] ?? 1;
        $_SESSION['authenticated'] = true;
        $_SESSION['last_activity'] = time();

        // Régénère l'ID de session pour éviter la fixation de session
        session_regenerate_id(true);
    }

    public static function logout(): void {
        session_unset();
        session_destroy();
    }

    public static function isAuthenticated(): bool {
        return isset($_SESSION['authenticated']) && $_SESSION['authenticated'] === true;
    }

    public static function getUserId(): ?int {
        return $_SESSION['user_id'] ?? null;
    }

    public static function getUserEmail(): ?string {
        return $_SESSION['user_email'] ?? null;
    }

    public static function getEntityId(): ?int {
        return $_SESSION['entity_id'] ?? null;
    }

    public static function getRole(): ?int {
        return $_SESSION['fk_role'] ?? null;
    }

    public static function requireAuth(): void {
        if (!self::isAuthenticated()) {
            // Log détaillé pour le debug
            $logFile = __DIR__ . '/../../logs/auth_' . date('Y-m-d') . '.log';
            $authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? 'No Authorization header';
            $appId = isset($_SERVER['HTTP_X_APP_IDENTIFIER']) ? $_SERVER['HTTP_X_APP_IDENTIFIER'] : 'No App Identifier';
            $method = $_SERVER['REQUEST_METHOD'] ?? 'Unknown Method';
            $uri = $_SERVER['REQUEST_URI'] ?? 'Unknown URI';
            
            $logMessage = "\n===== AUTHENTICATION FAILURE =====\n";
            $logMessage .= "Date: " . date('Y-m-d H:i:s') . "\n";
            $logMessage .= "Method: $method\n";
            $logMessage .= "URI: $uri\n";
            $logMessage .= "App ID: $appId\n";
            $logMessage .= "Auth Header: $authHeader\n";
            $logMessage .= "Session data: " . (isset($_SESSION) ? json_encode($_SESSION) : 'No session') . "\n";
            $logMessage .= "================================\n";
            
            file_put_contents($logFile, $logMessage, FILE_APPEND);
            
            Response::json(['error' => 'Non authentifié - Veuillez vous connecter'], 401);
            exit;
        }
    }

    // Vérification optionnelle de l'activité
    public static function checkActivity(): void {
        $inactiveTime = 3600; // 1 heure
        if (
            isset($_SESSION['last_activity']) &&
            (time() - $_SESSION['last_activity'] > $inactiveTime)
        ) {
            self::logout();
            Response::json(['error' => 'Session expirée'], 440);
            exit;
        }
        $_SESSION['last_activity'] = time();
    }

    // Récupère le session_id du Bearer token et le définit comme session_id courant
    private static function getSessionFromBearer(): void {
        // Vérifier si le header Authorization est présent
        $authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? '';

        // Mettre toutes les erreurs dans un fichier de log dédié
        $logFile = __DIR__ . '/../../logs/session_' . date('Y-m-d') . '.log';
        file_put_contents($logFile, date('Y-m-d H:i:s') . " - Auth Header: " . $authHeader . "\n", FILE_APPEND);

        // Nettoyage du header d'autorisation
        $authHeader = trim($authHeader);

        // Support de plusieurs formats possibles
        if (strpos($authHeader, 'Bearer ') === 0) {
            // Format standard "Bearer token"
            $sessionId = substr($authHeader, 7);
        } elseif (strpos(strtolower($authHeader), 'bearer ') === 0) {
            // Cas insensible à la casse
            $sessionId = substr($authHeader, 7);
        } elseif (preg_match('/^bearer\s+(.*)$/i', $authHeader, $matches)) {
            // Utilisation de l'expression régulière
            $sessionId = $matches[1];
        } else {
            file_put_contents($logFile, date('Y-m-d H:i:s') . " - No Bearer token found in Authorization header\n", FILE_APPEND);
            return;
        }

        // Nettoyage du token
        $sessionId = trim($sessionId);
        file_put_contents($logFile, date('Y-m-d H:i:s') . " - Session ID extracted: " . $sessionId . "\n", FILE_APPEND);

        // Vérifier que le session_id a un format valide (alphanumerique avec quelques caractères spéciaux)
        // Attention: les sessions en PHP peuvent contenir des caractères non-alphanumériques
        // Assouplir les règles de validation si nécessaire
        if (!empty($sessionId) && strlen($sessionId) <= 128) {
            // Définir l'ID de session avant de démarrer la session
            session_id($sessionId);
            file_put_contents($logFile, date('Y-m-d H:i:s') . " - Session ID set: " . $sessionId . "\n", FILE_APPEND);
        } else {
            file_put_contents($logFile, date('Y-m-d H:i:s') . " - Invalid session ID format in Bearer token\n", FILE_APPEND);
        }
    }
}
