<?php
/**
 * Optimized Session Handler for High Concurrency
 * Uses file-based sessions with proper locking for 100+ concurrent users
 */
class OptimizedSessionHandler implements SessionHandlerInterface {
    private string $savePath;
    private int $gcMaxLifetime;
    
    public function __construct(string $savePath = null, int $gcMaxLifetime = null) {
        $this->savePath = $savePath ?? (SESSION_PATH ?? APP_ROOT . '/storage/sessions');
        $this->gcMaxLifetime = $gcMaxLifetime ?? (SESSION_GC_MAXLIFETIME ?? 14400);
        
        if (!is_dir($this->savePath)) {
            mkdir($this->savePath, 0755, true);
        }
    }
    
    public function open(string $savePath, string $sessionName): bool {
        return true;
    }
    
    public function close(): bool {
        return true;
    }
    
    public function read(string $sessionId): string|false {
        $file = $this->getSessionFile($sessionId);
        
        if (!file_exists($file)) {
            return '';
        }
        
        // Use shared lock for reading to allow concurrent reads
        $fp = fopen($file, 'r');
        if (flock($fp, LOCK_SH)) {
            $data = stream_get_contents($fp);
            flock($fp, LOCK_UN);
            fclose($fp);
            return $data ?: '';
        }
        fclose($fp);
        return '';
    }
    
    public function write(string $sessionId, string $data): bool {
        $file = $this->getSessionFile($sessionId);
        
        // Use exclusive lock for writing to prevent race conditions
        $fp = fopen($file, 'c');
        if (flock($fp, LOCK_EX)) {
            ftruncate($fp, 0);
            fwrite($fp, $data);
            flock($fp, LOCK_UN);
            fclose($fp);
            return true;
        }
        fclose($fp);
        return false;
    }
    
    public function destroy(string $sessionId): bool {
        $file = $this->getSessionFile($sessionId);
        
        if (file_exists($file)) {
            return @unlink($file);
        }
        
        return true;
    }
    
    public function gc(int $maxlifetime): int|false {
        $count = 0;
        $now = time();
        $lifetime = $maxlifetime ?: $this->gcMaxLifetime;
        
        $files = glob($this->savePath . '/sess_*');
        
        foreach ($files as $file) {
            if ($now - filemtime($file) > $lifetime) {
                @unlink($file);
                $count++;
            }
        }
        
        return $count;
    }
    
    private function getSessionFile(string $sessionId): string {
        return $this->savePath . '/sess_' . $sessionId;
    }
}

/**
 * Initialize optimized session handler
 */
function initOptimizedSession(): void {
    if (SESSION_HANDLER === 'files') {
        $handler = new OptimizedSessionHandler();
        session_set_save_handler($handler, true);
    }
    
    session_name(SESSION_NAME);
    session_start();
    
    // Regenerate session ID periodically to prevent fixation
    if (!isset($_SESSION['created'])) {
        $_SESSION['created'] = time();
    } elseif (time() - $_SESSION['created'] > 1800) {
        session_regenerate_id(true);
        $_SESSION['created'] = time();
    }
}
