"""Unit tests for user permission system."""

import tempfile
from pathlib import Path
from unittest.mock import patch, mock_open
import pytest

from src.security.user_permissions import (
    UserPermissionSystem,
    Permission,
    Resource,
    User,
    check_permission,
    grant_permission,
    revoke_permission,
)


class TestUserPermissionSystem:
    """Test cases for UserPermissionSystem class."""

    def setup_method(self):
        """Set up test fixtures."""
        self.temp_dir = tempfile.mkdtemp()
        self.permissions_path = Path(self.temp_dir) / "permissions.json"

    def teardown_method(self):
        """Clean up test fixtures."""
        import shutil
        if self.temp_dir and Path(self.temp_dir).exists():
            shutil.rmtree(self.temp_dir)

    def test_init_creates_permissions_file(self):
        """Test that UserPermissionSystem creates permissions file if it doesn't exist."""
        # Permissions file shouldn't exist initially
        assert not self.permissions_path.exists()
        
        # Create UserPermissionSystem instance
        permission_system = UserPermissionSystem(self.permissions_path)
        
        # Permissions file should be created
        assert self.permissions_path.exists()

    def test_add_user(self):
        """Test adding a new user."""
        permission_system = UserPermissionSystem(self.permissions_path)
        
        # Add user
        user = User("test_user", "Test User")
        success = permission_system.add_user(user)
        
        assert success is True
        assert permission_system.get_user("test_user") == user

    def test_add_duplicate_user(self):
        """Test adding a user that already exists."""
        permission_system = UserPermissionSystem(self.permissions_path)
        
        # Add user first time
        user1 = User("test_user", "Test User")
        permission_system.add_user(user1)
        
        # Try to add same user again
        user2 = User("test_user", "Another User")
        success = permission_system.add_user(user2)
        
        assert success is False

    def test_remove_user(self):
        """Test removing a user."""
        permission_system = UserPermissionSystem(self.permissions_path)
        
        # Add user
        user = User("test_user", "Test User")
        permission_system.add_user(user)
        
        # Remove user
        success = permission_system.remove_user("test_user")
        assert success is True
        
        # User should be gone
        assert permission_system.get_user("test_user") is None

    def test_remove_nonexistent_user(self):
        """Test removing a user that doesn't exist."""
        permission_system = UserPermissionSystem(self.permissions_path)
        
        # Try to remove non-existent user
        success = permission_system.remove_user("nonexistent_user")
        assert success is False

    def test_grant_permission(self):
        """Test granting permission to a user."""
        permission_system = UserPermissionSystem(self.permissions_path)
        
        # Add user
        user = User("test_user", "Test User")
        permission_system.add_user(user)
        
        # Grant permission
        resource = Resource("file", "/path/to/file.txt")
        permission = Permission("read", resource)
        success = permission_system.grant_permission("test_user", permission)
        
        assert success is True
        
        # Check permission
        has_permission = permission_system.check_permission("test_user", permission)
        assert has_permission is True

    def test_grant_permission_to_nonexistent_user(self):
        """Test granting permission to a user that doesn't exist."""
        permission_system = UserPermissionSystem(self.permissions_path)
        
        # Try to grant permission to non-existent user
        resource = Resource("file", "/path/to/file.txt")
        permission = Permission("read", resource)
        success = permission_system.grant_permission("nonexistent_user", permission)
        
        assert success is False

    def test_revoke_permission(self):
        """Test revoking permission from a user."""
        permission_system = UserPermissionSystem(self.permissions_path)
        
        # Add user and grant permission
        user = User("test_user", "Test User")
        permission_system.add_user(user)
        
        resource = Resource("file", "/path/to/file.txt")
        permission = Permission("read", resource)
        permission_system.grant_permission("test_user", permission)
        
        # Revoke permission
        success = permission_system.revoke_permission("test_user", permission)
        assert success is True
        
        # Check permission is revoked
        has_permission = permission_system.check_permission("test_user", permission)
        assert has_permission is False

    def test_revoke_nonexistent_permission(self):
        """Test revoking a permission that doesn't exist."""
        permission_system = UserPermissionSystem(self.permissions_path)
        
        # Add user
        user = User("test_user", "Test User")
        permission_system.add_user(user)
        
        # Try to revoke non-existent permission
        resource = Resource("file", "/path/to/file.txt")
        permission = Permission("read", resource)
        success = permission_system.revoke_permission("test_user", permission)
        
        assert success is False

    def test_check_permission(self):
        """Test checking if a user has a specific permission."""
        permission_system = UserPermissionSystem(self.permissions_path)
        
        # Add user and grant permission
        user = User("test_user", "Test User")
        permission_system.add_user(user)
        
        resource = Resource("file", "/path/to/file.txt")
        permission = Permission("read", resource)
        permission_system.grant_permission("test_user", permission)
        
        # Check permission
        has_permission = permission_system.check_permission("test_user", permission)
        assert has_permission is True
        
        # Check non-existent permission
        other_permission = Permission("write", resource)
        has_other_permission = permission_system.check_permission("test_user", other_permission)
        assert has_other_permission is False

    def test_check_permission_for_nonexistent_user(self):
        """Test checking permission for a user that doesn't exist."""
        permission_system = UserPermissionSystem(self.permissions_path)
        
        # Try to check permission for non-existent user
        resource = Resource("file", "/path/to/file.txt")
        permission = Permission("read", resource)
        has_permission = permission_system.check_permission("nonexistent_user", permission)
        
        assert has_permission is False

    def test_list_user_permissions(self):
        """Test listing all permissions for a user."""
        permission_system = UserPermissionSystem(self.permissions_path)
        
        # Add user and grant multiple permissions
        user = User("test_user", "Test User")
        permission_system.add_user(user)
        
        resource1 = Resource("file", "/path/to/file1.txt")
        resource2 = Resource("file", "/path/to/file2.txt")
        permission1 = Permission("read", resource1)
        permission2 = Permission("write", resource2)
        
        permission_system.grant_permission("test_user", permission1)
        permission_system.grant_permission("test_user", permission2)
        
        # List permissions
        permissions = permission_system.list_user_permissions("test_user")
        assert len(permissions) == 2
        assert permission1 in permissions
        assert permission2 in permissions

    def test_list_permissions_for_nonexistent_user(self):
        """Test listing permissions for a user that doesn't exist."""
        permission_system = UserPermissionSystem(self.permissions_path)
        
        # Try to list permissions for non-existent user
        permissions = permission_system.list_user_permissions("nonexistent_user")
        assert permissions == []

    def test_list_all_users(self):
        """Test listing all users."""
        permission_system = UserPermissionSystem(self.permissions_path)
        
        # Add multiple users
        user1 = User("user1", "User One")
        user2 = User("user2", "User Two")
        
        permission_system.add_user(user1)
        permission_system.add_user(user2)
        
        # List all users
        users = permission_system.list_users()
        assert len(users) == 2
        assert user1 in users
        assert user2 in users

    def test_persist_and_load_permissions(self):
        """Test that permissions are persisted and loaded correctly."""
        permission_system = UserPermissionSystem(self.permissions_path)
        
        # Add user and grant permission
        user = User("test_user", "Test User")
        permission_system.add_user(user)
        
        resource = Resource("file", "/path/to/file.txt")
        permission = Permission("read", resource)
        permission_system.grant_permission("test_user", permission)
        
        # Create new instance (simulates restart)
        new_permission_system = UserPermissionSystem(self.permissions_path)
        
        # Check that user and permission still exist
        loaded_user = new_permission_system.get_user("test_user")
        assert loaded_user == user
        
        has_permission = new_permission_system.check_permission("test_user", permission)
        assert has_permission is True


class TestPermission:
    """Test cases for Permission class."""

    def test_permission_creation(self):
        """Test creating a permission."""
        resource = Resource("file", "/path/to/file.txt")
        permission = Permission("read", resource)
        
        assert permission.action == "read"
        assert permission.resource == resource

    def test_permission_equality(self):
        """Test permission equality."""
        resource1 = Resource("file", "/path/to/file.txt")
        resource2 = Resource("file", "/path/to/file.txt")
        
        permission1 = Permission("read", resource1)
        permission2 = Permission("read", resource2)
        permission3 = Permission("write", resource1)
        
        assert permission1 == permission2
        assert permission1 != permission3

    def test_permission_hash(self):
        """Test permission hash."""
        resource = Resource("file", "/path/to/file.txt")
        permission1 = Permission("read", resource)
        permission2 = Permission("read", resource)
        
        assert hash(permission1) == hash(permission2)


class TestResource:
    """Test cases for Resource class."""

    def test_resource_creation(self):
        """Test creating a resource."""
        resource = Resource("file", "/path/to/file.txt")
        
        assert resource.type == "file"
        assert resource.path == "/path/to/file.txt"

    def test_resource_equality(self):
        """Test resource equality."""
        resource1 = Resource("file", "/path/to/file.txt")
        resource2 = Resource("file", "/path/to/file.txt")
        resource3 = Resource("directory", "/path/to/file.txt")
        
        assert resource1 == resource2
        assert resource1 != resource3

    def test_resource_hash(self):
        """Test resource hash."""
        resource1 = Resource("file", "/path/to/file.txt")
        resource2 = Resource("file", "/path/to/file.txt")
        
        assert hash(resource1) == hash(resource2)


class TestUser:
    """Test cases for User class."""

    def test_user_creation(self):
        """Test creating a user."""
        user = User("test_user", "Test User")
        
        assert user.username == "test_user"
        assert user.display_name == "Test User"

    def test_user_equality(self):
        """Test user equality."""
        user1 = User("test_user", "Test User")
        user2 = User("test_user", "Test User")
        user3 = User("other_user", "Test User")
        
        assert user1 == user2
        assert user1 != user3

    def test_user_hash(self):
        """Test user hash."""
        user1 = User("test_user", "Test User")
        user2 = User("test_user", "Test User")
        
        assert hash(user1) == hash(user2)


class TestUtilityFunctions:
    """Test cases for utility functions."""

    def test_check_permission_utility(self):
        """Test check_permission utility function."""
        permission_system = UserPermissionSystem(self.permissions_path)
        
        # Add user and grant permission
        user = User("test_user", "Test User")
        permission_system.add_user(user)
        
        resource = Resource("file", "/path/to/file.txt")
        permission = Permission("read", resource)
        permission_system.grant_permission("test_user", permission)
        
        # Use utility function
        has_permission = check_permission(permission_system, "test_user", permission)
        assert has_permission is True

    def test_grant_permission_utility(self):
        """Test grant_permission utility function."""
        permission_system = UserPermissionSystem(self.permissions_path)
        
        # Add user
        user = User("test_user", "Test User")
        permission_system.add_user(user)
        
        # Use utility function
        resource = Resource("file", "/path/to/file.txt")
        permission = Permission("read", resource)
        success = grant_permission(permission_system, "test_user", permission)
        
        assert success is True

    def test_revoke_permission_utility(self):
        """Test revoke_permission utility function."""
        permission_system = UserPermissionSystem(self.permissions_path)
        
        # Add user and grant permission
        user = User("test_user", "Test User")
        permission_system.add_user(user)
        
        resource = Resource("file", "/path/to/file.txt")
        permission = Permission("read", resource)
        permission_system.grant_permission("test_user", permission)
        
        # Use utility function
        success = revoke_permission(permission_system, "test_user", permission)
        assert success is True
