<?php
/**
 * User Login Tracker Class
 * Handles tracking of user login activity
 */

namespace App\classes;

class UserLoginTracker {
    private $conn;
    
    public function __construct($connection) {
        $this->conn = $connection;
    }
    
    /**
     * Log user login
     */
    public function logLogin($userId, $username, $userRole, $ipAddress, $userAgent, $status = 'success', $failureReason = null) {
        // For failed logins with non-existent users, set user_id to NULL
        if ($status === 'failed' && ($userId === 0 || $userId === null)) {
            $userId = null;
        }
        
        $stmt = $this->conn->prepare("
            INSERT INTO user_login_logs (user_id, username, user_role, ip_address, user_agent, login_status, failure_reason)
            VALUES (?, ?, ?, ?, ?, ?, ?)
        ");
        
        $stmt->bind_param("issssss", $userId, $username, $userRole, $ipAddress, $userAgent, $status, $failureReason);
        
        if ($stmt->execute()) {
            $logId = $this->conn->insert_id;
            $stmt->close();
            return $logId;
        } else {
            $stmt->close();
            return false;
        }
    }
    
    /**
     * Log user logout
     */
    public function logLogout($userId, $loginTime = null) {
        if ($loginTime === null) {
            // Find the most recent login for this user
            $stmt = $this->conn->prepare("
                SELECT id, created_at as login_time FROM user_login_logs 
                WHERE user_id = ? AND logout_time IS NULL 
                ORDER BY created_at DESC LIMIT 1
            ");
            $stmt->bind_param("i", $userId);
            $stmt->execute();
            $result = $stmt->get_result();
            
            if ($result->num_rows > 0) {
                $row = $result->fetch_assoc();
                $logId = $row['id'];
                $loginTime = $row['login_time'];
            } else {
                $stmt->close();
                return false;
            }
            $stmt->close();
        } else {
            // Find login log by time
            $stmt = $this->conn->prepare("
                SELECT id FROM user_login_logs 
                WHERE user_id = ? AND created_at = ? AND logout_time IS NULL
            ");
            $stmt->bind_param("is", $userId, $loginTime);
            $stmt->execute();
            $result = $stmt->get_result();
            
            if ($result->num_rows > 0) {
                $row = $result->fetch_assoc();
                $logId = $row['id'];
            } else {
                $stmt->close();
                return false;
            }
            $stmt->close();
        }
        
        // Calculate session duration
        $sessionDuration = time() - strtotime($loginTime);
        
        // Update logout time
        $stmt = $this->conn->prepare("
            UPDATE user_login_logs 
            SET logout_time = NOW(), session_duration = ?
            WHERE id = ?
        ");
        $stmt->bind_param("ii", $sessionDuration, $logId);
        $success = $stmt->execute();
        $stmt->close();
        
        return $success;
    }
    
    /**
     * Get recent login activity
     */
    public function getRecentLogins($limit = 50, $userId = null, $status = null, $days = null) {
        // First check if the table exists
        $tableCheck = $this->conn->query("SHOW TABLES LIKE 'user_login_logs'");
        if (!$tableCheck || $tableCheck->num_rows == 0) {
            error_log("Table user_login_logs does not exist");
            return [];
        }
        
        // Check if agents table exists and has the required columns
        $agentsTableCheck = $this->conn->query("SHOW TABLES LIKE 'agents'");
        $agentsExists = $agentsTableCheck && $agentsTableCheck->num_rows > 0;
        
        $canJoin = false;
        if ($agentsExists) {
            // Check if agents table has the required columns
            $emailCheck = $this->conn->query("SHOW COLUMNS FROM agents LIKE 'email'");
            $roleCheck = $this->conn->query("SHOW COLUMNS FROM agents LIKE 'role'");
            $canJoin = ($emailCheck && $emailCheck->num_rows > 0) && ($roleCheck && $roleCheck->num_rows > 0);
        }
        
        // Choose query based on whether we can join with agents table
        if ($canJoin) {
            // Try the full query with JOIN
            $sql = "
                SELECT 
                    ull.id,
                    ull.user_id,
                    ull.username,
                    ull.user_role,
                    ull.ip_address,
                    ull.user_agent,
                    ull.login_status,
                    ull.failure_reason,
                    ull.created_at,
                    ull.logout_time,
                    ull.session_duration,
                    a.email,
                    a.role as `current_role`
                FROM user_login_logs ull
                LEFT JOIN agents a ON ull.user_id = a.id
                WHERE 1=1
            ";
        } else {
            // Use fallback query without JOIN
            $sql = "
                SELECT 
                    ull.id,
                    ull.user_id,
                    ull.username,
                    ull.user_role,
                    ull.ip_address,
                    ull.user_agent,
                    ull.login_status,
                    ull.failure_reason,
                    ull.created_at,
                    ull.logout_time,
                    ull.session_duration,
                    NULL as email,
                    ull.user_role as `current_role`
                FROM user_login_logs ull
                WHERE 1=1
            ";
        }
        
        $params = [];
        $types = "";
        
        if ($userId !== null) {
            $sql .= " AND ull.user_id = ?";
            $params[] = $userId;
            $types .= "i";
        }
        
        if ($status !== null && $status !== '') {
            $sql .= " AND ull.login_status = ?";
            $params[] = $status;
            $types .= "s";
        }
        
        if ($days !== null && $days > 0) {
            $sql .= " AND ull.created_at >= DATE_SUB(NOW(), INTERVAL ? DAY)";
            $params[] = $days;
            $types .= "i";
        }
        
        $sql .= " ORDER BY ull.created_at DESC LIMIT ?";
        $params[] = $limit;
        $types .= "i";
        
        $stmt = $this->conn->prepare($sql);
        if (!$stmt) {
            error_log("SQL Prepare Error: " . $this->conn->error);
            error_log("SQL Query: " . $sql);
            return [];
        }
        
        if (!empty($params)) {
            $stmt->bind_param($types, ...$params);
        }
        
        if (!$stmt->execute()) {
            error_log("SQL Execute Error: " . $stmt->error);
            $stmt->close();
            return [];
        }
        
        $result = $stmt->get_result();
        
        $logins = [];
        while ($row = $result->fetch_assoc()) {
            $logins[] = $row;
        }
        
        $stmt->close();
        return $logins;
    }
    
    /**
     * Get user login statistics
     */
    public function getUserLoginStats($userId = null, $days = 30) {
        $sql = "
            SELECT 
                DATE(created_at) as date,
                COUNT(*) as total_logins,
                COUNT(CASE WHEN login_status = 'success' THEN 1 END) as successful_logins,
                COUNT(CASE WHEN login_status = 'failed' THEN 1 END) as failed_logins,
                AVG(session_duration) as avg_session_duration
            FROM user_login_logs 
            WHERE created_at >= DATE_SUB(NOW(), INTERVAL ? DAY)
        ";
        
        $params = [$days];
        $types = "i";
        
        if ($userId !== null) {
            $sql .= " AND user_id = ?";
            $params[] = $userId;
            $types .= "i";
        }
        
        $sql .= " GROUP BY DATE(created_at) ORDER BY date DESC";
        
        $stmt = $this->conn->prepare($sql);
        $stmt->bind_param($types, ...$params);
        $stmt->execute();
        $result = $stmt->get_result();
        
        $stats = [];
        while ($row = $result->fetch_assoc()) {
            $stats[] = $row;
        }
        
        $stmt->close();
        return $stats;
    }
    
    /**
     * Get active sessions (users currently logged in)
     */
    public function getActiveSessions() {
        // First check if the table exists
        $tableCheck = $this->conn->query("SHOW TABLES LIKE 'user_login_logs'");
        if (!$tableCheck || $tableCheck->num_rows == 0) {
            error_log("Table user_login_logs does not exist");
            return [];
        }
        
        // Check if agents table exists and has the required columns
        $agentsTableCheck = $this->conn->query("SHOW TABLES LIKE 'agents'");
        $agentsExists = $agentsTableCheck && $agentsTableCheck->num_rows > 0;
        
        $canJoin = false;
        if ($agentsExists) {
            // Check if agents table has the required columns
            $emailCheck = $this->conn->query("SHOW COLUMNS FROM agents LIKE 'email'");
            $roleCheck = $this->conn->query("SHOW COLUMNS FROM agents LIKE 'role'");
            $canJoin = ($emailCheck && $emailCheck->num_rows > 0) && ($roleCheck && $roleCheck->num_rows > 0);
        }
        
        // Choose query based on whether we can join with agents table
        if ($canJoin) {
            // Try the full query with JOIN
            $sql = "
                SELECT 
                    ull.id,
                    ull.user_id,
                    ull.username,
                    ull.user_role,
                    ull.ip_address,
                    ull.user_agent,
                    ull.login_status,
                    ull.failure_reason,
                    ull.created_at,
                    ull.logout_time,
                    ull.session_duration,
                    a.email,
                    a.role as `current_role`
                FROM user_login_logs ull
                LEFT JOIN agents a ON ull.user_id = a.id
                WHERE ull.logout_time IS NULL 
                AND ull.created_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
                ORDER BY ull.created_at DESC
            ";
        } else {
            // Use fallback query without JOIN
            $sql = "
                SELECT 
                    ull.id,
                    ull.user_id,
                    ull.username,
                    ull.user_role,
                    ull.ip_address,
                    ull.user_agent,
                    ull.login_status,
                    ull.failure_reason,
                    ull.created_at,
                    ull.logout_time,
                    ull.session_duration,
                    NULL as email,
                    ull.user_role as `current_role`
                FROM user_login_logs ull
                WHERE ull.logout_time IS NULL 
                AND ull.created_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
                ORDER BY ull.created_at DESC
            ";
        }
        
        $stmt = $this->conn->prepare($sql);
        if (!$stmt) {
            error_log("SQL Prepare Error: " . $this->conn->error);
            error_log("SQL Query: " . $sql);
            return [];
        }
        
        if (!$stmt->execute()) {
            error_log("SQL Execute Error: " . $stmt->error);
            $stmt->close();
            return [];
        }
        
        $result = $stmt->get_result();
        
        $sessions = [];
        while ($row = $result->fetch_assoc()) {
            $sessions[] = $row;
        }
        
        $stmt->close();
        return $sessions;
    }
    
    /**
     * Get login summary statistics
     */
    public function getLoginSummary($days = 30) {
        $stmt = $this->conn->prepare("
            SELECT 
                COUNT(*) as total_logins,
                COUNT(CASE WHEN login_status = 'success' THEN 1 END) as successful_logins,
                COUNT(CASE WHEN login_status = 'failed' THEN 1 END) as failed_logins,
                COUNT(DISTINCT user_id) as unique_users,
                AVG(session_duration) as avg_session_duration
            FROM user_login_logs 
            WHERE created_at >= DATE_SUB(NOW(), INTERVAL ? DAY)
        ");
        
        $stmt->bind_param("i", $days);
        $stmt->execute();
        $result = $stmt->get_result();
        $summary = $result->fetch_assoc();
        $stmt->close();
        
        return $summary;
    }
    
    /**
     * Get top users by login frequency
     */
    public function getTopUsersByLogins($limit = 10, $days = 30) {
        $stmt = $this->conn->prepare("
            SELECT 
                ull.user_id,
                ull.username,
                ull.user_role,
                COUNT(*) as login_count,
                MAX(ull.created_at) as last_login,
                AVG(ull.session_duration) as avg_session_duration
            FROM user_login_logs ull
            WHERE ull.created_at >= DATE_SUB(NOW(), INTERVAL ? DAY)
            AND ull.login_status = 'success'
            GROUP BY ull.user_id, ull.username, ull.user_role
            ORDER BY login_count DESC
            LIMIT ?
        ");
        
        $stmt->bind_param("ii", $days, $limit);
        $stmt->execute();
        $result = $stmt->get_result();
        
        $users = [];
        while ($row = $result->fetch_assoc()) {
            $users[] = $row;
        }
        
        $stmt->close();
        return $users;
    }
    
    /**
     * Clean old login logs
     */
    public function cleanOldLogs($days = 90) {
        $stmt = $this->conn->prepare("
            DELETE FROM user_login_logs 
            WHERE created_at < DATE_SUB(NOW(), INTERVAL ? DAY)
        ");
        
        $stmt->bind_param("i", $days);
        $success = $stmt->execute();
        $deletedCount = $stmt->affected_rows;
        $stmt->close();
        
        return [
            'success' => $success,
            'deleted_count' => $deletedCount
        ];
    }
    
    /**
     * Format session duration
     */
    public static function formatSessionDuration($seconds) {
        if ($seconds === null) {
            return 'N/A';
        }
        
        // Convert to integer to avoid precision loss warnings
        $seconds = (int) $seconds;
        
        $hours = floor($seconds / 3600);
        $minutes = floor(($seconds % 3600) / 60);
        $seconds = $seconds % 60;
        
        if ($hours > 0) {
            return sprintf('%dh %dm %ds', $hours, $minutes, $seconds);
        } elseif ($minutes > 0) {
            return sprintf('%dm %ds', $minutes, $seconds);
        } else {
            return sprintf('%ds', $seconds);
        }
    }
    
    /**
     * Get IP address from request
     */
    public static function getClientIP() {
        $ipKeys = ['HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'REMOTE_ADDR'];
        
        foreach ($ipKeys as $key) {
            if (array_key_exists($key, $_SERVER) === true) {
                foreach (explode(',', $_SERVER[$key]) as $ip) {
                    $ip = trim($ip);
                    if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false) {
                        return $ip;
                    }
                }
            }
        }
        
        return $_SERVER['REMOTE_ADDR'] ?? 'unknown';
    }
    
    /**
     * Get user agent from request
     */
    public static function getUserAgent() {
        return $_SERVER['HTTP_USER_AGENT'] ?? 'unknown';
    }
    
}
?>

