<?php
/**
 * Authentication & Authorization Class
 */
class Auth {
    
    /**
     * Attempt to login user
     */
    public static function attempt($username, $password, $remember = false) {
        // Check rate limiting
        if (!self::checkRateLimit($_SERVER['REMOTE_ADDR'])) {
            return ['success' => false, 'message' => 'Too many login attempts. Please try again later.'];
        }
        
        // Get user by username/email
        $user = Database::fetchOne(
            "SELECT * FROM users WHERE (username = ? OR email = ?) AND is_active = 1",
            [$username, $username]
        );
        
        if (!$user) {
            self::recordFailedAttempt($_SERVER['REMOTE_ADDR']);
            return ['success' => false, 'message' => 'Invalid credentials'];
        }
        
        // Check if account is locked
        if ($user['lockout_until'] && strtotime($user['lockout_until']) > time()) {
            return ['success' => false, 'message' => 'Account is temporarily locked. Please try again later.'];
        }
        
        // Verify password
        if (!password_verify($password, $user['password_hash'])) {
            self::recordFailedAttempt($_SERVER['REMOTE_ADDR']);
            self::incrementLoginAttempts($user['id']);
            return ['success' => false, 'message' => 'Invalid credentials'];
        }
        
        // Check if 2FA is enabled
        if ($user['two_factor_enabled']) {
            Session::set('2fa_user_id', $user['id']);
            return ['success' => true, 'requires_2fa' => true];
        }
        
        // Login successful
        self::loginUser($user, $remember);
        
        return ['success' => true, 'requires_2fa' => false];
    }
    
    /**
     * Complete login after successful 2FA
     */
    public static function completeTwoFactorLogin($userId, $remember = false) {
        $user = Database::fetchOne("SELECT * FROM users WHERE id = ? AND is_active = 1", [$userId]);
        
        if (!$user) {
            return false;
        }
        
        self::loginUser($user, $remember);
        Session::remove('2fa_user_id');
        
        return true;
    }
    
    /**
     * Login user - set session variables
     */
    private static function loginUser($user, $remember = false) {
        // Reset login attempts
        Database::update('users', 
            ['login_attempts' => 0, 'lockout_until' => null, 'last_login' => date('Y-m-d H:i:s'), 'last_ip' => $_SERVER['REMOTE_ADDR']],
            'id = ?', [$user['id']]
        );
        
        // Set session
        Session::regenerate();
        Session::set('user_id', $user['id']);
        Session::set('username', $user['username']);
        Session::set('full_name', $user['full_name']);
        Session::set('email', $user['email']);
        Session::set('nis_number', $user['nis_number']);
        Session::set('rank', $user['rank']);
        Session::set('logged_in', true);
        Session::set('login_time', time());
        
        // Get user roles
        $roles = Database::fetchAll(
            "SELECT r.role_name FROM user_roles ur 
             JOIN roles r ON ur.role_id = r.id 
             WHERE ur.user_id = ?",
            [$user['id']]
        );
        Session::set('roles', array_column($roles, 'role_name'));
        
        // Get user permissions
        $permissions = self::getUserPermissions($user['id']);
        Session::set('permissions', $permissions);
        
        // Set remember me cookie
        if ($remember) {
            $token = bin2hex(random_bytes(32));
            $expires = time() + 30 * 24 * 60 * 60; // 30 days
            
            setcookie('remember_token', $token, $expires, '/', '', true, true);
            
            Database::insert('user_sessions', [
                'user_id' => $user['id'],
                'session_token' => $token,
                'ip_address' => $_SERVER['REMOTE_ADDR'],
                'user_agent' => $_SERVER['HTTP_USER_AGENT'],
                'login_time' => date('Y-m-d H:i:s'),
                'last_activity' => date('Y-m-d H:i:s'),
                'expires_at' => date('Y-m-d H:i:s', $expires),
                'is_active' => 1
            ]);
        }
        
        // Log audit
        AuditLogger::log('LOGIN_SUCCESS', 'users', $user['id'], null, 'User logged in successfully');
    }
    
    /**
     * Check if user is logged in
     */
    public static function check() {
        return Session::has('user_id') && Session::get('logged_in') === true;
    }
    
    /**
     * Get current user ID
     */
    public static function id() {
        return Session::get('user_id');
    }
    
    /**
     * Get current user data
     */
    public static function user() {
        if (!self::check()) {
            return null;
        }
        
        return Database::fetchOne("SELECT * FROM users WHERE id = ?", [self::id()]);
    }
    
    /**
     * Check if user has a specific role
     */
    public static function hasRole($role) {
        $roles = Session::get('roles', []);
        
        // Super Admin has all roles
        if (in_array('Super Admin Officer', $roles)) {
            return true;
        }
        
        return in_array($role, $roles);
    }
    
    /**
     * Check if user has any of the given roles
     */
    public static function hasAnyRole($roles) {
        $userRoles = Session::get('roles', []);
        
        // Super Admin has all roles
        if (in_array('Super Admin Officer', $userRoles)) {
            return true;
        }
        
        foreach ($roles as $role) {
            if (in_array($role, $userRoles)) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * Check if user has a specific permission
     */
    public static function can($permission) {
        $permissions = Session::get('permissions', []);
        
        // Super Admin has all permissions
        if (in_array('Super Admin Officer', Session::get('roles', []))) {
            return true;
        }
        
        return in_array($permission, $permissions);
    }
    
    /**
     * Check if user has any of the given permissions
     */
    public static function canAny($permissions) {
        // Super Admin has all permissions
        if (in_array('Super Admin Officer', Session::get('roles', []))) {
            return true;
        }
        
        $userPermissions = Session::get('permissions', []);
        
        foreach ($permissions as $permission) {
            if (in_array($permission, $userPermissions)) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * Check if user has all of the given permissions
     */
    public static function canAll($permissions) {
        // Super Admin has all permissions
        if (in_array('Super Admin Officer', Session::get('roles', []))) {
            return true;
        }
        
        $userPermissions = Session::get('permissions', []);
        
        foreach ($permissions as $permission) {
            if (!in_array($permission, $userPermissions)) {
                return false;
            }
        }
        return true;
    }
    
    /**
     * Require authentication - redirect if not logged in
     */
    public static function requireAuth() {
        if (!self::check()) {
            header('Location: ' . Config::get('app_url') . '/auth/login');
            exit();
        }
    }
    
    /**
     * Require specific permission - redirect if not authorized
     */
    public static function requirePermission($permission) {
        self::requireAuth();
        
        if (!self::can($permission)) {
            header('Location: ' . Config::get('app_url') . '/auth/unauthorized');
            exit();
        }
    }
    
    /**
     * Require any of the given permissions
     */
    public static function requireAnyPermission($permissions) {
        self::requireAuth();
        
        if (!self::canAny($permissions)) {
            header('Location: ' . Config::get('app_url') . '/auth/unauthorized');
            exit();
        }
    }
    
    /**
     * Get all permissions for a user
     */
    private static function getUserPermissions($userId) {
        $sql = "SELECT DISTINCT p.permission_key 
                FROM permissions p
                JOIN role_permissions rp ON p.id = rp.permission_id
                JOIN user_roles ur ON rp.role_id = ur.role_id
                WHERE ur.user_id = ? AND (rp.can_view = 1 OR rp.can_create = 1 OR rp.can_edit = 1 OR rp.can_delete = 1 OR rp.can_approve = 1)";
        
        $permissions = Database::fetchAll($sql, [$userId]);
        return array_column($permissions, 'permission_key');
    }
    
    /**
     * Check rate limiting for IP address
     */
    private static function checkRateLimit($ip) {
        $maxAttempts = Config::get('max_login_attempts', 5);
        $lockoutTime = Config::get('lockout_time', 900); // 15 minutes
        
        $attempts = Database::fetchOne(
            "SELECT COUNT(*) as count, MAX(created_at) as last_attempt 
             FROM audit_logs 
             WHERE ip_address = ? AND action = 'LOGIN_FAILED' 
             AND created_at > DATE_SUB(NOW(), INTERVAL ? SECOND)",
            [$ip, $lockoutTime]
        );
        
        return $attempts['count'] < $maxAttempts;
    }
    
    /**
     * Record failed login attempt
     */
    private static function recordFailedAttempt($ip) {
        AuditLogger::log('LOGIN_FAILED', null, null, null, 'Failed login attempt', null, null, $ip);
    }
    
    /**
     * Increment login attempts for user
     */
    private static function incrementLoginAttempts($userId) {
        $user = Database::fetchOne("SELECT login_attempts FROM users WHERE id = ?", [$userId]);
        
        $attempts = ($user['login_attempts'] ?? 0) + 1;
        $lockoutUntil = null;
        
        if ($attempts >= Config::get('max_login_attempts', 5)) {
            $lockoutUntil = date('Y-m-d H:i:s', time() + Config::get('lockout_time', 900));
        }
        
        Database::update('users', 
            ['login_attempts' => $attempts, 'lockout_until' => $lockoutUntil],
            'id = ?', [$userId]
        );
    }
    
    /**
     * Logout user
     */
    public static function logout() {
        // Log audit
        if (self::check()) {
            AuditLogger::log('LOGOUT', 'users', self::id(), null, 'User logged out');
            
            // Invalidate remember token
            if (isset($_COOKIE['remember_token'])) {
                Database::update('user_sessions', 
                    ['is_active' => 0],
                    'session_token = ? AND user_id = ?',
                    [$_COOKIE['remember_token'], self::id()]
                );
                setcookie('remember_token', '', time() - 3600, '/', '', true, true);
            }
        }
        
        Session::destroy();
    }
}