"""
Comprehensive Unit Tests for Permission Services

This module contains unit tests for all permission checking logic,
role template application, and permission management services.
"""

from django.test import TestCase, TransactionTestCase
from django.core.cache import cache
from django.utils import timezone
from django.contrib.auth import get_user_model
from unittest.mock import patch, MagicMock, call
from decimal import Decimal
from datetime import date, timedelta

from users.models import Branch, RolePermission, DefaultRolePermission, UserPermission
from users.enhanced_permissions_models import (
    PagePermission, RolePermissionTemplate, UserPagePermission
)
from users.services import PagePermissionManager, RolePermissionTemplateManager
from users.permission_cache_service import PermissionCacheService
from users.enhanced_user_methods import EnhancedUserMethods

User = get_user_model()


class PagePermissionManagerTest(TestCase):
    """Test cases for PagePermissionManager service"""
    
    def setUp(self):
        """Set up test data"""
        # Clear cache before each test
        cache.clear()
        
        # Create test branch
        self.branch = Branch.objects.create(
            name="Test Branch",
            code="TB001",
            is_active=True
        )
        
        # Create test users
        self.admin = User.objects.create_user(
            username="admin",
            email="admin@test.com",
            password="testpass123",
            role="admin",
            branch=self.branch,
            phone_number="+254700000001"
        )
        
        self.loan_officer = User.objects.create_user(
            username="officer1",
            email="officer1@test.com",
            password="testpass123",
            role="loan_officer",
            branch=self.branch,
            phone_number="+254700000002"
        )
        
        # Create test page permissions
        self.loans_view_perm = PagePermission.objects.create(
            page_name="loans",
            action_code="loans_view_applications",
            action_name="View Loan Applications",
            description="Allow viewing loan applications",
            category="view",
            is_critical=False
        )
        
        self.loans_create_perm = PagePermission.objects.create(
            page_name="loans",
            action_code="loans_create_application",
            action_name="Create Loan Application",
            description="Allow creating loan applications",
            category="create",
            is_critical=True
        )
        
        self.loans_approve_perm = PagePermission.objects.create(
            page_name="loans",
            action_code="loans_approve_application",
            action_name="Approve Loan Application",
            description="Allow approving loan applications",
            category="approve",
            is_critical=True
        )
        
        # Create role permission templates
        RolePermissionTemplate.objects.create(
            role="loan_officer",
            page_permission=self.loans_view_perm,
            is_allowed=True
        )
        
        RolePermissionTemplate.objects.create(
            role="loan_officer",
            page_permission=self.loans_create_perm,
            is_allowed=True
        )
        
        RolePermissionTemplate.objects.create(
            role="loan_officer",
            page_permission=self.loans_approve_perm,
            is_allowed=False
        )
        
        # Initialize service
        self.permission_manager = PagePermissionManager()
    
    def test_get_page_permissions_from_role_template(self):
        """Test getting page permissions from role templates"""
        permissions = self.permission_manager.get_page_permissions(self.loan_officer, "loans")
        
        # Verify permissions
        self.assertTrue(permissions["loans_view_applications"])
        self.assertTrue(permissions["loans_create_application"])
        self.assertFalse(permissions["loans_approve_application"])
    
    def test_get_page_permissions_with_user_override(self):
        """Test getting page permissions with user-specific overrides"""
        # Create user override that allows approval
        UserPagePermission.objects.create(
            user=self.loan_officer,
            page_permission=self.loans_approve_perm,
            is_allowed=True,
            granted_by=self.admin,
            reason="Special approval permission for testing"
        )
        
        permissions = self.permission_manager.get_page_permissions(self.loan_officer, "loans")
        
        # User override should take precedence
        self.assertTrue(permissions["loans_approve_application"])
    
    def test_check_action_permission_allowed(self):
        """Test checking specific action permission when allowed"""
        has_permission = self.permission_manager.check_action_permission(
            self.loan_officer, "loans", "loans_view_applications"
        )
        self.assertTrue(has_permission)
    
    def test_check_action_permission_denied(self):
        """Test checking specific action permission when denied"""
        has_permission = self.permission_manager.check_action_permission(
            self.loan_officer, "loans", "loans_approve_application"
        )
        self.assertFalse(has_permission)
    
    def test_check_action_permission_nonexistent(self):
        """Test checking permission for non-existent action"""
        has_permission = self.permission_manager.check_action_permission(
            self.loan_officer, "loans", "loans_nonexistent_action"
        )
        self.assertFalse(has_permission)
    
    def test_get_available_actions(self):
        """Test getting list of available actions for user"""
        available_actions = self.permission_manager.get_available_actions(
            self.loan_officer, "loans"
        )
        
        # Should include allowed actions only
        self.assertIn("loans_view_applications", available_actions)
        self.assertIn("loans_create_application", available_actions)
        self.assertNotIn("loans_approve_application", available_actions)
    
    def test_permission_caching(self):
        """Test that permissions are properly cached"""
        # Mock the cache service
        with patch.object(self.permission_manager.cache_service, 'get_user_page_permissions') as mock_get:
            with patch.object(self.permission_manager.cache_service, 'set_user_page_permissions') as mock_set:
                mock_get.return_value = None  # Cache miss
                
                # First call should hit database and cache result
                permissions = self.permission_manager.get_page_permissions(self.loan_officer, "loans")
                
                # Verify cache was checked and set
                mock_get.assert_called_once_with(str(self.loan_officer.id), "loans")
                mock_set.assert_called_once()
                
                # Second call should hit cache
                mock_get.return_value = permissions  # Cache hit
                permissions2 = self.permission_manager.get_page_permissions(self.loan_officer, "loans")
                
                # Verify cache was used
                self.assertEqual(mock_get.call_count, 2)
                self.assertEqual(mock_set.call_count, 1)  # Only set once
    
    def test_permission_inheritance_hierarchy(self):
        """Test permission inheritance from role to user"""
        # Admin should have all permissions
        admin_permissions = self.permission_manager.get_page_permissions(self.admin, "loans")
        
        # Admin should have access to all actions
        self.assertTrue(admin_permissions["loans_view_applications"])
        self.assertTrue(admin_permissions["loans_create_application"])
        self.assertTrue(admin_permissions["loans_approve_application"])
    
    def test_expired_user_permissions(self):
        """Test that expired user permissions are not applied"""
        # Create expired user permission
        expired_date = timezone.now() - timedelta(days=1)
        UserPagePermission.objects.create(
            user=self.loan_officer,
            page_permission=self.loans_approve_perm,
            is_allowed=True,
            granted_by=self.admin,
            expires_at=expired_date,
            reason="Expired permission for testing"
        )
        
        permissions = self.permission_manager.get_page_permissions(self.loan_officer, "loans")
        
        # Expired permission should not be applied
        self.assertFalse(permissions["loans_approve_application"])
    
    def test_critical_permission_handling(self):
        """Test handling of critical permissions"""
        # Critical permissions should be logged when accessed
        with patch('users.services.logger') as mock_logger:
            self.permission_manager.check_action_permission(
                self.loan_officer, "loans", "loans_create_application"
            )
            
            # Should log access to critical permission
            mock_logger.info.assert_called()


class RolePermissionTemplateManagerTest(TestCase):
    """Test cases for RolePermissionTemplateManager service"""
    
    def setUp(self):
        """Set up test data"""
        self.branch = Branch.objects.create(
            name="Test Branch",
            code="TB001",
            is_active=True
        )
        
        self.admin = User.objects.create_user(
            username="admin",
            email="admin@test.com",
            password="testpass123",
            role="admin",
            branch=self.branch,
            phone_number="+254700000001"
        )
        
        # Create test page permissions
        self.loans_view_perm = PagePermission.objects.create(
            page_name="loans",
            action_code="loans_view_applications",
            action_name="View Loan Applications",
            description="Allow viewing loan applications",
            category="view"
        )
        
        self.loans_create_perm = PagePermission.objects.create(
            page_name="loans",
            action_code="loans_create_application",
            action_name="Create Loan Application",
            description="Allow creating loan applications",
            category="create"
        )
        
        # Initialize service
        self.template_manager = RolePermissionTemplateManager()
    
    def test_set_role_defaults(self):
        """Test setting default permissions for a role"""
        permissions_dict = {
            "loans_view_applications": True,
            "loans_create_application": True,
            "loans_approve_application": False
        }
        
        result = self.template_manager.set_role_defaults("loan_officer", permissions_dict)
        
        # Verify result
        self.assertTrue(result["success"])
        self.assertEqual(result["permissions_set"], 2)  # Only 2 permissions exist
        
        # Verify templates were created
        templates = RolePermissionTemplate.objects.filter(role="loan_officer")
        self.assertEqual(templates.count(), 2)
    
    def test_get_role_defaults(self):
        """Test getting default permissions for a role"""
        # Create role templates
        RolePermissionTemplate.objects.create(
            role="loan_officer",
            page_permission=self.loans_view_perm,
            is_allowed=True
        )
        
        RolePermissionTemplate.objects.create(
            role="loan_officer",
            page_permission=self.loans_create_perm,
            is_allowed=False
        )
        
        defaults = self.template_manager.get_role_defaults("loan_officer")
        
        # Verify defaults
        self.assertTrue(defaults["loans_view_applications"])
        self.assertFalse(defaults["loans_create_application"])
    
    def test_apply_defaults_to_users(self):
        """Test applying role defaults to users"""
        # Create role template
        RolePermissionTemplate.objects.create(
            role="loan_officer",
            page_permission=self.loans_view_perm,
            is_allowed=True
        )
        
        # Create loan officer
        loan_officer = User.objects.create_user(
            username="officer1",
            email="officer1@test.com",
            password="testpass123",
            role="loan_officer",
            branch=self.branch,
            phone_number="+254700000002"
        )
        
        result = self.template_manager.apply_defaults_to_users("loan_officer")
        
        # Verify result
        self.assertTrue(result["success"])
        self.assertEqual(result["users_updated"], 1)
        
        # Verify user permission was created
        user_perm = UserPagePermission.objects.filter(
            user=loan_officer,
            page_permission=self.loans_view_perm
        ).first()
        self.assertIsNotNone(user_perm)
        self.assertTrue(user_perm.is_allowed)
    
    def test_validate_permission_combinations(self):
        """Test validation of permission combinations"""
        # Test valid combination
        permissions = {
            "loans_view_applications": True,
            "loans_create_application": True
        }
        
        is_valid, issues = self.template_manager.validate_permission_combinations(permissions)
        self.assertTrue(is_valid)
        self.assertEqual(len(issues), 0)
        
        # Test invalid combination (create without view)
        invalid_permissions = {
            "loans_view_applications": False,
            "loans_create_application": True
        }
        
        is_valid, issues = self.template_manager.validate_permission_combinations(invalid_permissions)
        self.assertFalse(is_valid)
        self.assertTrue(len(issues) > 0)
    
    def test_get_role_template(self):
        """Test getting role template with metadata"""
        # Create role templates
        RolePermissionTemplate.objects.create(
            role="loan_officer",
            page_permission=self.loans_view_perm,
            is_allowed=True,
            can_override=True
        )
        
        template = self.template_manager.get_role_template("loan_officer")
        
        # Verify template structure
        self.assertIn("role", template)
        self.assertIn("permissions", template)
        self.assertIn("metadata", template)
        self.assertEqual(template["role"], "loan_officer")
        self.assertTrue(template["permissions"]["loans_view_applications"])


class PermissionCacheServiceTest(TestCase):
    """Test cases for PermissionCacheService"""
    
    def setUp(self):
        """Set up test data"""
        cache.clear()
        self.cache_service = PermissionCacheService()
        self.user_id = "test-user-123"
        self.page_name = "loans"
        self.permissions = {
            "loans_view_applications": True,
            "loans_create_application": False
        }
    
    def test_set_and_get_user_page_permissions(self):
        """Test setting and getting user page permissions from cache"""
        # Set permissions
        self.cache_service.set_user_page_permissions(
            self.user_id, self.page_name, self.permissions
        )
        
        # Get permissions
        cached_permissions = self.cache_service.get_user_page_permissions(
            self.user_id, self.page_name
        )
        
        # Verify cached permissions
        self.assertEqual(cached_permissions, self.permissions)
    
    def test_invalidate_user_permissions(self):
        """Test invalidating user permissions cache"""
        # Set permissions
        self.cache_service.set_user_page_permissions(
            self.user_id, self.page_name, self.permissions
        )
        
        # Verify permissions are cached
        cached_permissions = self.cache_service.get_user_page_permissions(
            self.user_id, self.page_name
        )
        self.assertIsNotNone(cached_permissions)
        
        # Invalidate cache
        self.cache_service.invalidate_user_permissions(self.user_id)
        
        # Verify permissions are no longer cached
        cached_permissions = self.cache_service.get_user_page_permissions(
            self.user_id, self.page_name
        )
        self.assertIsNone(cached_permissions)
    
    def test_warm_cache_for_user(self):
        """Test warming cache for user"""
        # Mock user and permissions
        mock_user = MagicMock()
        mock_user.id = self.user_id
        mock_user.role = "loan_officer"
        
        with patch('users.permission_cache_service.PagePermissionManager') as mock_manager:
            mock_manager_instance = mock_manager.return_value
            mock_manager_instance.get_page_permissions.return_value = self.permissions
            
            # Warm cache
            result = self.cache_service.warm_cache_for_user(mock_user, ["loans", "clients"])
            
            # Verify result
            self.assertTrue(result["success"])
            self.assertEqual(result["pages_cached"], 2)
    
    def test_get_cache_stats(self):
        """Test getting cache statistics"""
        # Set some permissions
        self.cache_service.set_user_page_permissions(
            self.user_id, self.page_name, self.permissions
        )
        
        # Get cache stats
        stats = self.cache_service.get_cache_stats()
        
        # Verify stats structure
        self.assertIn("total_keys", stats)
        self.assertIn("permission_keys", stats)
        self.assertIn("memory_usage", stats)


class EnhancedUserMethodsTest(TestCase):
    """Test cases for enhanced user methods"""
    
    def setUp(self):
        """Set up test data"""
        self.branch = Branch.objects.create(
            name="Test Branch",
            code="TB001",
            is_active=True
        )
        
        self.loan_officer = User.objects.create_user(
            username="officer1",
            email="officer1@test.com",
            password="testpass123",
            role="loan_officer",
            branch=self.branch,
            phone_number="+254700000002"
        )
        
        # Create test page permission
        self.loans_view_perm = PagePermission.objects.create(
            page_name="loans",
            action_code="loans_view_applications",
            action_name="View Loan Applications",
            description="Allow viewing loan applications",
            category="view"
        )
        
        # Create role template
        RolePermissionTemplate.objects.create(
            role="loan_officer",
            page_permission=self.loans_view_perm,
            is_allowed=True
        )
    
    def test_has_page_permission(self):
        """Test has_page_permission method"""
        has_permission = self.loan_officer.has_page_permission("loans", "loans_view_applications")
        self.assertTrue(has_permission)
        
        has_permission = self.loan_officer.has_page_permission("loans", "loans_nonexistent")
        self.assertFalse(has_permission)
    
    def test_get_page_permissions(self):
        """Test get_page_permissions method"""
        permissions = self.loan_officer.get_page_permissions("loans")
        
        self.assertIsInstance(permissions, dict)
        self.assertIn("loans_view_applications", permissions)
        self.assertTrue(permissions["loans_view_applications"])
    
    def test_get_effective_permissions_enhanced(self):
        """Test get_effective_permissions_enhanced method"""
        permissions = self.loan_officer.get_effective_permissions_enhanced()
        
        # Verify structure
        self.assertIn("permissions", permissions)
        self.assertIn("system", permissions)
        self.assertIn("user_info", permissions)
        self.assertIn("role_defaults", permissions)
        self.assertIn("custom_overrides", permissions)
    
    def test_get_available_page_actions(self):
        """Test get_available_page_actions method"""
        actions = self.loan_officer.get_available_page_actions("loans")
        
        self.assertIsInstance(actions, list)
        self.assertIn("loans_view_applications", actions)
    
    def test_get_permission_source(self):
        """Test get_permission_source method"""
        source = self.loan_officer.get_permission_source("loans", "loans_view_applications")
        
        self.assertIn("source", source)
        self.assertIn("details", source)
        self.assertEqual(source["source"], "role_template")


class PermissionValidationTest(TestCase):
    """Test cases for permission validation logic"""
    
    def setUp(self):
        """Set up test data"""
        self.branch = Branch.objects.create(
            name="Test Branch",
            code="TB001",
            is_active=True
        )
        
        # Create test permissions with dependencies
        self.view_perm = PagePermission.objects.create(
            page_name="loans",
            action_code="loans_view_applications",
            action_name="View Loan Applications",
            description="Allow viewing loan applications",
            category="view"
        )
        
        self.create_perm = PagePermission.objects.create(
            page_name="loans",
            action_code="loans_create_application",
            action_name="Create Loan Application",
            description="Allow creating loan applications",
            category="create"
        )
        
        # Set up dependency (create requires view)
        self.create_perm.required_permissions.add(self.view_perm)
    
    def test_permission_dependency_validation(self):
        """Test validation of permission dependencies"""
        from users.permission_validation import PermissionValidator
        
        validator = PermissionValidator()
        
        # Test valid combination (has view and create)
        permissions = {
            "loans_view_applications": True,
            "loans_create_application": True
        }
        
        is_valid, issues = validator.validate_permission_set(permissions)
        self.assertTrue(is_valid)
        
        # Test invalid combination (has create but not view)
        invalid_permissions = {
            "loans_view_applications": False,
            "loans_create_application": True
        }
        
        is_valid, issues = validator.validate_permission_set(invalid_permissions)
        self.assertFalse(is_valid)
        self.assertTrue(len(issues) > 0)
    
    def test_critical_permission_validation(self):
        """Test validation of critical permissions"""
        from users.permission_validation import PermissionValidator
        
        # Mark create permission as critical
        self.create_perm.is_critical = True
        self.create_perm.save()
        
        validator = PermissionValidator()
        
        # Test granting critical permission
        permissions = {
            "loans_create_application": True
        }
        
        validation_result = validator.validate_critical_permissions(permissions, "loan_officer")
        
        # Should require additional validation for critical permissions
        self.assertIn("critical_permissions", validation_result)
        self.assertTrue(len(validation_result["critical_permissions"]) > 0)


class PermissionAuditTest(TestCase):
    """Test cases for permission audit functionality"""
    
    def setUp(self):
        """Set up test data"""
        self.branch = Branch.objects.create(
            name="Test Branch",
            code="TB001",
            is_active=True
        )
        
        self.admin = User.objects.create_user(
            username="admin",
            email="admin@test.com",
            password="testpass123",
            role="admin",
            branch=self.branch,
            phone_number="+254700000001"
        )
        
        self.loan_officer = User.objects.create_user(
            username="officer1",
            email="officer1@test.com",
            password="testpass123",
            role="loan_officer",
            branch=self.branch,
            phone_number="+254700000002"
        )
    
    def test_permission_change_audit(self):
        """Test auditing of permission changes"""
        from users.audit_service import AuditService
        
        audit_service = AuditService()
        
        # Create page permission
        page_perm = PagePermission.objects.create(
            page_name="loans",
            action_code="loans_view_applications",
            action_name="View Loan Applications",
            description="Allow viewing loan applications",
            category="view"
        )
        
        # Grant permission to user
        user_perm = UserPagePermission.objects.create(
            user=self.loan_officer,
            page_permission=page_perm,
            is_allowed=True,
            granted_by=self.admin,
            reason="Testing permission audit"
        )
        
        # Audit the permission grant
        audit_entry = audit_service.log_permission_change(
            user=self.admin,
            target_user=self.loan_officer,
            action="grant_permission",
            permission_code="loans_view_applications",
            details={"reason": "Testing permission audit"}
        )
        
        # Verify audit entry
        self.assertIsNotNone(audit_entry)
        self.assertEqual(audit_entry.action, "grant_permission")
        self.assertEqual(audit_entry.target_user, self.loan_officer)
    
    def test_permission_access_audit(self):
        """Test auditing of permission access"""
        from users.audit_service import AuditService
        
        audit_service = AuditService()
        
        # Log permission access
        audit_entry = audit_service.log_permission_access(
            user=self.loan_officer,
            page_name="loans",
            action="loans_view_applications",
            result="allowed",
            ip_address="192.168.1.1"
        )
        
        # Verify audit entry
        self.assertIsNotNone(audit_entry)
        self.assertEqual(audit_entry.user, self.loan_officer)
        self.assertEqual(audit_entry.page_name, "loans")
        self.assertEqual(audit_entry.result, "allowed")


class PermissionPerformanceTest(TestCase):
    """Test cases for permission system performance"""
    
    def setUp(self):
        """Set up test data"""
        self.branch = Branch.objects.create(
            name="Test Branch",
            code="TB001",
            is_active=True
        )
        
        # Create multiple users for performance testing
        self.users = []
        for i in range(10):
            user = User.objects.create_user(
                username=f"user{i}",
                email=f"user{i}@test.com",
                password="testpass123",
                role="loan_officer",
                branch=self.branch,
                phone_number=f"+25470000000{i}"
            )
            self.users.append(user)
        
        # Create multiple page permissions
        self.permissions = []
        for i in range(20):
            perm = PagePermission.objects.create(
                page_name="loans",
                action_code=f"loans_action_{i}",
                action_name=f"Loan Action {i}",
                description=f"Allow loan action {i}",
                category="view"
            )
            self.permissions.append(perm)
            
            # Create role templates for each permission
            RolePermissionTemplate.objects.create(
                role="loan_officer",
                page_permission=perm,
                is_allowed=True
            )
    
    def test_bulk_permission_checking_performance(self):
        """Test performance of bulk permission checking"""
        import time
        
        permission_manager = PagePermissionManager()
        
        start_time = time.time()
        
        # Check permissions for all users
        for user in self.users:
            permissions = permission_manager.get_page_permissions(user, "loans")
            self.assertIsInstance(permissions, dict)
            self.assertTrue(len(permissions) > 0)
        
        end_time = time.time()
        execution_time = end_time - start_time
        
        # Should complete within reasonable time (adjust threshold as needed)
        self.assertLess(execution_time, 5.0, "Bulk permission checking took too long")
    
    def test_cache_effectiveness(self):
        """Test cache effectiveness for repeated permission checks"""
        import time
        
        permission_manager = PagePermissionManager()
        user = self.users[0]
        
        # First call (cache miss)
        start_time = time.time()
        permissions1 = permission_manager.get_page_permissions(user, "loans")
        first_call_time = time.time() - start_time
        
        # Second call (cache hit)
        start_time = time.time()
        permissions2 = permission_manager.get_page_permissions(user, "loans")
        second_call_time = time.time() - start_time
        
        # Verify results are identical
        self.assertEqual(permissions1, permissions2)
        
        # Cache hit should be significantly faster
        self.assertLess(second_call_time, first_call_time * 0.5)


class PermissionErrorHandlingTest(TestCase):
    """Test cases for permission system error handling"""
    
    def setUp(self):
        """Set up test data"""
        self.branch = Branch.objects.create(
            name="Test Branch",
            code="TB001",
            is_active=True
        )
        
        self.user = User.objects.create_user(
            username="testuser",
            email="test@test.com",
            password="testpass123",
            role="loan_officer",
            branch=self.branch,
            phone_number="+254700000001"
        )
    
    def test_database_error_handling(self):
        """Test handling of database errors"""
        permission_manager = PagePermissionManager()
        
        # Mock database error
        with patch('users.enhanced_permissions_models.PagePermission.objects.filter') as mock_filter:
            mock_filter.side_effect = Exception("Database connection error")
            
            # Should handle error gracefully
            permissions = permission_manager.get_page_permissions(self.user, "loans")
            
            # Should return empty permissions dict on error
            self.assertIsInstance(permissions, dict)
    
    def test_cache_error_handling(self):
        """Test handling of cache errors"""
        permission_manager = PagePermissionManager()
        
        # Mock cache error
        with patch.object(permission_manager.cache_service, 'get_user_page_permissions') as mock_get:
            mock_get.side_effect = Exception("Cache connection error")
            
            # Should handle cache error and fall back to database
            permissions = permission_manager.get_page_permissions(self.user, "loans")
            
            # Should still return permissions (from database fallback)
            self.assertIsInstance(permissions, dict)
    
    def test_invalid_user_handling(self):
        """Test handling of invalid user objects"""
        permission_manager = PagePermissionManager()
        
        # Test with None user
        permissions = permission_manager.get_page_permissions(None, "loans")
        self.assertEqual(permissions, {})
        
        # Test with user without role
        invalid_user = MagicMock()
        invalid_user.role = None
        invalid_user.id = "test-id"
        
        permissions = permission_manager.get_page_permissions(invalid_user, "loans")
        self.assertIsInstance(permissions, dict)
    
    def test_invalid_page_name_handling(self):
        """Test handling of invalid page names"""
        permission_manager = PagePermissionManager()
        
        # Test with empty page name
        permissions = permission_manager.get_page_permissions(self.user, "")
        self.assertEqual(permissions, {})
        
        # Test with None page name
        permissions = permission_manager.get_page_permissions(self.user, None)
        self.assertEqual(permissions, {})
        
        # Test with non-existent page
        permissions = permission_manager.get_page_permissions(self.user, "nonexistent_page")
        self.assertIsInstance(permissions, dict)


class PermissionIntegrationTest(TransactionTestCase):
    """Integration tests for permission system components"""
    
    def setUp(self):
        """Set up test data"""
        self.branch = Branch.objects.create(
            name="Test Branch",
            code="TB001",
            is_active=True
        )
        
        self.admin = User.objects.create_user(
            username="admin",
            email="admin@test.com",
            password="testpass123",
            role="admin",
            branch=self.branch,
            phone_number="+254700000001"
        )
        
        self.loan_officer = User.objects.create_user(
            username="officer1",
            email="officer1@test.com",
            password="testpass123",
            role="loan_officer",
            branch=self.branch,
            phone_number="+254700000002"
        )
    
    def test_end_to_end_permission_workflow(self):
        """Test complete permission workflow from setup to checking"""
        # 1. Create page permissions
        view_perm = PagePermission.objects.create(
            page_name="loans",
            action_code="loans_view_applications",
            action_name="View Loan Applications",
            description="Allow viewing loan applications",
            category="view"
        )
        
        create_perm = PagePermission.objects.create(
            page_name="loans",
            action_code="loans_create_application",
            action_name="Create Loan Application",
            description="Allow creating loan applications",
            category="create"
        )
        
        # 2. Set up role templates
        template_manager = RolePermissionTemplateManager()
        result = template_manager.set_role_defaults("loan_officer", {
            "loans_view_applications": True,
            "loans_create_application": False
        })
        self.assertTrue(result["success"])
        
        # 3. Apply defaults to users
        result = template_manager.apply_defaults_to_users("loan_officer")
        self.assertTrue(result["success"])
        
        # 4. Check permissions
        permission_manager = PagePermissionManager()
        permissions = permission_manager.get_page_permissions(self.loan_officer, "loans")
        
        self.assertTrue(permissions["loans_view_applications"])
        self.assertFalse(permissions["loans_create_application"])
        
        # 5. Grant custom permission
        UserPagePermission.objects.create(
            user=self.loan_officer,
            page_permission=create_perm,
            is_allowed=True,
            granted_by=self.admin,
            reason="Special permission for testing"
        )
        
        # 6. Verify custom permission overrides role default
        # Clear cache to ensure fresh data
        cache.clear()
        permissions = permission_manager.get_page_permissions(self.loan_officer, "loans")
        
        self.assertTrue(permissions["loans_view_applications"])
        self.assertTrue(permissions["loans_create_application"])  # Should be overridden
    
    def test_permission_system_with_multiple_roles(self):
        """Test permission system with multiple user roles"""
        # Create permissions
        approve_perm = PagePermission.objects.create(
            page_name="loans",
            action_code="loans_approve_application",
            action_name="Approve Loan Application",
            description="Allow approving loan applications",
            category="approve",
            is_critical=True
        )
        
        # Set up different role templates
        template_manager = RolePermissionTemplateManager()
        
        # Loan officers cannot approve
        template_manager.set_role_defaults("loan_officer", {
            "loans_approve_application": False
        })
        
        # Team leaders can approve
        template_manager.set_role_defaults("team_leader", {
            "loans_approve_application": True
        })
        
        # Create team leader
        team_leader = User.objects.create_user(
            username="leader1",
            email="leader1@test.com",
            password="testpass123",
            role="team_leader",
            branch=self.branch,
            phone_number="+254700000003"
        )
        
        # Apply defaults
        template_manager.apply_defaults_to_users("loan_officer")
        template_manager.apply_defaults_to_users("team_leader")
        
        # Check permissions
        permission_manager = PagePermissionManager()
        
        officer_permissions = permission_manager.get_page_permissions(self.loan_officer, "loans")
        leader_permissions = permission_manager.get_page_permissions(team_leader, "loans")
        
        self.assertFalse(officer_permissions["loans_approve_application"])
        self.assertTrue(leader_permissions["loans_approve_application"])