<?php
/**
 * (c) ININOUT & PYXIS. All Rights Reserved.
 * Wszelkie modyfikacje tego pliku wymagaja zgloszenia oraz zgody autorow.
 * Any modifications to this file require notification and consent of the authors.
 */
/**
 * i-BOK 5 - Bezpieczne zarządzanie sesjami
 */

if (session_status() === PHP_SESSION_NONE) {
    $secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off');

    session_name(defined('IBOK_SESSION_NAME') ? IBOK_SESSION_NAME : 'IBOK_SESSION');

    session_set_cookie_params([
        'lifetime' => 0,
        'path'     => '/',
        'domain'   => '',
        'secure'   => $secure,
        'httponly'  => true,
        'samesite'  => 'Strict',
    ]);

    session_start();
}

// Generowanie CSP nonce (raz na request)
if (empty($_SESSION['_csp_nonce']) || !isset($GLOBALS['_csp_nonce'])) {
    $GLOBALS['_csp_nonce'] = base64_encode(random_bytes(16));
}

// Nagłówki bezpieczeństwa
if (!headers_sent()) {
    header('X-Frame-Options: SAMEORIGIN');
    header('X-Content-Type-Options: nosniff');
    header('X-XSS-Protection: 1; mode=block');
    header('Referrer-Policy: strict-origin-when-cross-origin');

    // CSP z nonce
    $nonce = $GLOBALS['_csp_nonce'] ?? '';
    header("Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{$nonce}' 'strict-dynamic'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'self'");
}

// Rejestracja aktywnych sesji
if (!empty($_SESSION['logged_in'])) {
    session_register_activity();
}

/**
 * Aktualizuj wpis sesji w active_sessions.json
 */
function session_register_activity() {
    $sessions_file = (defined('IBOK_LOGS_DIR') ? IBOK_LOGS_DIR : __DIR__ . '/../logs') . '/active_sessions.json';
    $session_hash = md5(session_id());

    $sessions = [];
    if (file_exists($sessions_file)) {
        $sessions = @json_decode(file_get_contents($sessions_file), true) ?: [];
    }

    // Wyczyść wygasłe sesje (starsze niż 30 min)
    $timeout = defined('IBOK_SESSION_TIMEOUT') ? IBOK_SESSION_TIMEOUT : 1800;
    $now = time();
    foreach ($sessions as $hash => $s) {
        if (($now - ($s['last_activity'] ?? 0)) > $timeout) {
            unset($sessions[$hash]);
        }
    }

    // Aktualizuj bieżącą sesję
    $sessions[$session_hash] = [
        'user_type'     => $_SESSION['user_type'] ?? 'unknown',
        'login'         => ($_SESSION['user_type'] ?? '') === 'admin'
                            ? ($_SESSION['admin_login'] ?? '')
                            : ($_SESSION['client_login'] ?? ''),
        'ip'            => $_SERVER['REMOTE_ADDR'] ?? '',
        'started'       => $sessions[$session_hash]['started'] ?? $now,
        'last_activity' => $now,
        'user_agent'    => $_SERVER['HTTP_USER_AGENT'] ?? '',
    ];

    @file_put_contents($sessions_file, json_encode($sessions, JSON_PRETTY_PRINT), LOCK_EX);
}

/**
 * Usuń sesję z rejestru (przy wylogowaniu)
 */
function session_unregister() {
    $sessions_file = (defined('IBOK_LOGS_DIR') ? IBOK_LOGS_DIR : __DIR__ . '/../logs') . '/active_sessions.json';
    $session_hash = md5(session_id());

    if (!file_exists($sessions_file)) return;

    $sessions = @json_decode(file_get_contents($sessions_file), true) ?: [];
    unset($sessions[$session_hash]);
    @file_put_contents($sessions_file, json_encode($sessions, JSON_PRETTY_PRINT), LOCK_EX);
}

/**
 * Odczytaj aktywne sesje (z czyszczeniem wygasłych)
 */
function session_get_active() {
    $sessions_file = (defined('IBOK_LOGS_DIR') ? IBOK_LOGS_DIR : __DIR__ . '/../logs') . '/active_sessions.json';
    if (!file_exists($sessions_file)) return [];

    $sessions = @json_decode(file_get_contents($sessions_file), true) ?: [];
    $timeout = defined('IBOK_SESSION_TIMEOUT') ? IBOK_SESSION_TIMEOUT : 1800;
    $now = time();
    $active = [];

    foreach ($sessions as $hash => $s) {
        if (($now - ($s['last_activity'] ?? 0)) <= $timeout) {
            $active[$hash] = $s;
        }
    }

    return $active;
}

/**
 * Wymuś wylogowanie sesji po hash
 */
function session_force_logout($target_hash) {
    $sessions_file = (defined('IBOK_LOGS_DIR') ? IBOK_LOGS_DIR : __DIR__ . '/../logs') . '/active_sessions.json';
    if (!file_exists($sessions_file)) return false;

    $sessions = @json_decode(file_get_contents($sessions_file), true) ?: [];
    if (!isset($sessions[$target_hash])) return false;

    unset($sessions[$target_hash]);
    @file_put_contents($sessions_file, json_encode($sessions, JSON_PRETTY_PRINT), LOCK_EX);

    // Zniszcz plik sesji PHP (jeśli handler to files)
    $save_path = session_save_path() ?: sys_get_temp_dir();
    // Musimy znaleźć prawdziwy session ID - iterujemy pliki sesji
    // Nie mamy bezpośredniego mapowania hash -> session_id, więc po prostu usuwamy z JSON
    // Sesja wygaśnie naturalnie przy następnym request (brak wpisu w JSON)

    return true;
}
