<?php
/**
 * Session - Session management library
 */

class Session
{
    private static bool $started = false;

    public static function start(?int $lifetime = null): void
    {
        if (self::$started || session_status() === PHP_SESSION_ACTIVE) {
            return;
        }

        $lifetime = $lifetime ?? (defined('SESSION_LIFETIME') ? SESSION_LIFETIME : 3600);
        $name     = defined('SESSION_NAME')     ? SESSION_NAME     : 'app_session';

        // Doit être réglé AVANT session_start() (sinon « session is active »).
        ini_set('session.gc_maxlifetime', (string)$lifetime);

        session_name($name);
        session_set_cookie_params([
            'lifetime' => $lifetime,
            'path'     => '/',
            'secure'   => self::isSecureRequest(),
            'httponly' => true,
            'samesite' => 'Lax',
        ]);

        session_start();
        self::$started = true;

        // Regenerate session ID periodically to prevent fixation
        if (empty($_SESSION['_created'])) {
            $_SESSION['_created'] = time();
        } elseif (time() - $_SESSION['_created'] > 300) {
            session_regenerate_id(true);
            $_SESSION['_created'] = time();
        }
    }

    /**
     * Détermine si la requête est servie en HTTPS, y compris derrière un
     * reverse-proxy terminant le TLS (X-Forwarded-Proto). `SESSION_FORCE_SECURE`
     * peut forcer le flag Secure en production quel que soit l'environnement.
     */
    private static function isSecureRequest(): bool
    {
        if (defined('SESSION_FORCE_SECURE') && SESSION_FORCE_SECURE) {
            return true;
        }
        if (!empty($_SERVER['HTTPS']) && strtolower((string)$_SERVER['HTTPS']) !== 'off') {
            return true;
        }
        $proto = $_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '';
        return strtolower(explode(',', $proto)[0] ?? '') === 'https';
    }

    public static function set(string $key, mixed $value): void
    {
        $_SESSION[$key] = $value;
    }

    public static function get(string $key, mixed $default = null): mixed
    {
        return $_SESSION[$key] ?? $default;
    }

    public static function has(string $key): bool
    {
        return isset($_SESSION[$key]);
    }

    public static function remove(string $key): void
    {
        unset($_SESSION[$key]);
    }

    public static function setFlash(string $key, string $message): void
    {
        $_SESSION['_flash'][$key] = $message;
    }

    public static function getFlash(string $key): ?string
    {
        $msg = $_SESSION['_flash'][$key] ?? null;
        unset($_SESSION['_flash'][$key]);
        return $msg;
    }

    public static function destroy(): void
    {
        $_SESSION = [];
        if (ini_get('session.use_cookies')) {
            $params = session_get_cookie_params();
            setcookie(
                session_name(),
                '',
                time() - 42000,
                $params['path'],
                $params['domain'],
                $params['secure'],
                $params['httponly']
            );
        }
        session_destroy();
        self::$started = false;
    }
}
