<?php

namespace App\Core;

/**
 * Session Manager - إدارة محسّنة للجلسات
 * يدعم: timeout warnings, concurrent sessions, remember me
 */
class SessionManager
{
    private \PDO $db;
    private Logger $logger;
    private array $config;
    private int $warningTime;
    private int $maxConcurrentSessions;

    public function __construct(\PDO $db, Logger $logger, array $config)
    {
        $this->db = $db;
        $this->logger = $logger;
        $this->config = $config;
        $this->warningTime = ($config['session']['lifetime'] ?? 1800) - 300; // 5 دقائق قبل الانتهاء
        $this->maxConcurrentSessions = $config['session']['max_concurrent'] ?? 3;
        
        $this->ensureTableExists();
    }

    /**
     * التأكد من وجود جدول user_sessions
     */
    private function ensureTableExists(): void
    {
        try {
            $this->db->query('SELECT id FROM user_sessions LIMIT 1');
        } catch (\Throwable $e) {
            $sql = "CREATE TABLE IF NOT EXISTS user_sessions (
                id VARCHAR(128) PRIMARY KEY,
                user_id INT NOT NULL,
                user_type ENUM('admin', 'doctor') DEFAULT 'admin',
                ip_address VARCHAR(45),
                user_agent TEXT,
                last_activity TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                expires_at TIMESTAMP NOT NULL,
                remember_me BOOLEAN DEFAULT FALSE,
                INDEX idx_user_id (user_id),
                INDEX idx_expires_at (expires_at),
                INDEX idx_last_activity (last_activity)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";
            $this->db->exec($sql);
        }
    }

    /**
     * بدء جلسة جديدة
     */
    public function start(int $userId, string $userType = 'admin', bool $rememberMe = false): string
    {
        $sessionId = session_id();
        $lifetime = $rememberMe ? 2592000 : ($this->config['session']['lifetime'] ?? 1800); // 30 يوم أو 30 دقيقة
        $expiresAt = date('Y-m-d H:i:s', time() + $lifetime);

        // التحقق من عدد الجلسات المتزامنة
        $this->enforceConcurrentSessions($userId, $userType);

        // حفظ الجلسة في قاعدة البيانات
        $stmt = $this->db->prepare("
            INSERT INTO user_sessions (id, user_id, user_type, ip_address, user_agent, expires_at, remember_me)
            VALUES (?, ?, ?, ?, ?, ?, ?)
            ON DUPLICATE KEY UPDATE
                last_activity = NOW(),
                expires_at = VALUES(expires_at),
                remember_me = VALUES(remember_me)
        ");

        $stmt->execute([
            $sessionId,
            $userId,
            $userType,
            $_SERVER['REMOTE_ADDR'] ?? '',
            $_SERVER['HTTP_USER_AGENT'] ?? '',
            $expiresAt,
            $rememberMe ? 1 : 0
        ]);

        // تحديث إعدادات الجلسة
        if ($rememberMe) {
            ini_set('session.cookie_lifetime', 2592000);
        }

        $this->logger->info("Session started", [
            'user_id' => $userId,
            'user_type' => $userType,
            'remember_me' => $rememberMe
        ]);

        return $sessionId;
    }

    /**
     * التحقق من صحة الجلسة
     */
    public function validate(): bool
    {
        $sessionId = session_id();
        if (empty($sessionId)) {
            return false;
        }

        $stmt = $this->db->prepare("
            SELECT user_id, user_type, expires_at, last_activity
            FROM user_sessions
            WHERE id = ? AND expires_at > NOW()
        ");
        $stmt->execute([$sessionId]);
        $session = $stmt->fetch();

        if (!$session) {
            $this->destroy();
            return false;
        }

        // تحديث last_activity
        $this->db->prepare("UPDATE user_sessions SET last_activity = NOW() WHERE id = ?")->execute([$sessionId]);

        return true;
    }

    /**
     * التحقق من الحاجة لتحذير timeout
     */
    public function shouldWarnTimeout(): bool
    {
        $sessionId = session_id();
        if (empty($sessionId)) {
            return false;
        }

        $stmt = $this->db->prepare("
            SELECT TIMESTAMPDIFF(SECOND, NOW(), expires_at) as seconds_left
            FROM user_sessions
            WHERE id = ?
        ");
        $stmt->execute([$sessionId]);
        $result = $stmt->fetch();

        if ($result && (int)$result['seconds_left'] <= $this->warningTime) {
            return true;
        }

        return false;
    }

    /**
     * جلب الوقت المتبقي للجلسة
     */
    public function getTimeRemaining(): int
    {
        $sessionId = session_id();
        if (empty($sessionId)) {
            return 0;
        }

        $stmt = $this->db->prepare("
            SELECT TIMESTAMPDIFF(SECOND, NOW(), expires_at) as seconds_left
            FROM user_sessions
            WHERE id = ?
        ");
        $stmt->execute([$sessionId]);
        $result = $stmt->fetch();

        return $result ? max(0, (int)$result['seconds_left']) : 0;
    }

    /**
     * تمديد الجلسة
     */
    public function extend(int $additionalSeconds = 1800): void
    {
        $sessionId = session_id();
        if (empty($sessionId)) {
            return;
        }

        $stmt = $this->db->prepare("
            UPDATE user_sessions
            SET expires_at = DATE_ADD(expires_at, INTERVAL ? SECOND),
                last_activity = NOW()
            WHERE id = ?
        ");
        $stmt->execute([$additionalSeconds, $sessionId]);
    }

    /**
     * إنهاء الجلسة
     */
    public function destroy(): void
    {
        $sessionId = session_id();
        if (!empty($sessionId)) {
            $this->db->prepare("DELETE FROM user_sessions WHERE id = ?")->execute([$sessionId]);
        }
        
        session_destroy();
    }

    /**
     * إنهاء جميع جلسات المستخدم
     */
    public function destroyAll(int $userId, string $userType = 'admin'): void
    {
        $this->db->prepare("DELETE FROM user_sessions WHERE user_id = ? AND user_type = ?")->execute([$userId, $userType]);
        $this->logger->info("All sessions destroyed", ['user_id' => $userId, 'user_type' => $userType]);
    }

    /**
     * إنهاء الجلسات القديمة
     */
    public function cleanup(): int
    {
        $stmt = $this->db->query("DELETE FROM user_sessions WHERE expires_at < NOW()");
        $deleted = $stmt->rowCount();
        
        if ($deleted > 0) {
            $this->logger->info("Expired sessions cleaned", ['count' => $deleted]);
        }
        
        return $deleted;
    }

    /**
     * فرض حد الجلسات المتزامنة
     */
    private function enforceConcurrentSessions(int $userId, string $userType): void
    {
        // جلب الجلسات النشطة
        $stmt = $this->db->prepare("
            SELECT id
            FROM user_sessions
            WHERE user_id = ? AND user_type = ? AND expires_at > NOW()
            ORDER BY last_activity DESC
        ");
        $stmt->execute([$userId, $userType]);
        $sessions = $stmt->fetchAll();

        // حذف الجلسات الزائدة
        if (count($sessions) >= $this->maxConcurrentSessions) {
            $sessionsToDelete = array_slice($sessions, $this->maxConcurrentSessions - 1);
            foreach ($sessionsToDelete as $session) {
                $this->db->prepare("DELETE FROM user_sessions WHERE id = ?")->execute([$session['id']]);
            }
            
            $this->logger->info("Concurrent sessions limited", [
                'user_id' => $userId,
                'deleted' => count($sessionsToDelete)
            ]);
        }
    }

    /**
     * جلب جميع جلسات المستخدم
     */
    public function getUserSessions(int $userId, string $userType = 'admin'): array
    {
        $stmt = $this->db->prepare("
            SELECT id, ip_address, user_agent, last_activity, created_at, expires_at, remember_me
            FROM user_sessions
            WHERE user_id = ? AND user_type = ? AND expires_at > NOW()
            ORDER BY last_activity DESC
        ");
        $stmt->execute([$userId, $userType]);
        return $stmt->fetchAll();
    }
}
