#!/usr/bin/env python
"""
Comprehensive test script to verify all permissions are enforced correctly
Tests that permissions actually control access to features
"""
import os
import sys
import django

# Setup Django
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'branch_system.settings')
django.setup()

from django.contrib.auth import get_user_model
from users.models import CustomUser, UserPermission, RolePermission, DefaultRolePermission
from django.db import transaction

CustomUser = get_user_model()

def test_permission_enforcement():
    """Test that permissions actually prevent access"""
    print("=" * 80)
    print("PERMISSION ENFORCEMENT TEST")
    print("=" * 80)
    
    # Create a test staff user
    print("\n1. Creating test staff user...")
    try:
        test_user = CustomUser.objects.get(email='test_staff_permissions@test.com')
        print(f"   Using existing user: {test_user.get_full_name()}")
    except CustomUser.DoesNotExist:
        test_user = CustomUser.objects.create_user(
            username='test_staff_permissions',
            email='test_staff_permissions@test.com',
            password='testpass123',
            first_name='Test',
            last_name='Staff',
            role='loan_officer',
            is_staff=True,
            phone_number='+254712345678'  # Add phone number to avoid unique constraint
        )
        print(f"   Created user: {test_user.get_full_name()}")
    
    # Test 1: Client Create Permission
    print("\n2. Testing Client Create Permission...")
    
    # Remove all custom permissions
    UserPermission.objects.filter(user=test_user, module='clients', action='create').delete()
    
    # Test without permission
    has_create = test_user.has_permission('clients', 'create')
    print(f"   Client create permission (should be False): {has_create}")
    assert not has_create, "ERROR: User should NOT have client create permission!"
    
    # Grant permission
    UserPermission.objects.create(
        user=test_user,
        module='clients',
        action='create',
        is_allowed=True,
        granted_by=CustomUser.objects.filter(role='admin').first()
    )
    
    # Test with permission
    has_create = test_user.has_permission('clients', 'create')
    print(f"   Client create permission (should be True): {has_create}")
    assert has_create, "ERROR: User should have client create permission!"
    
    # Revoke permission
    UserPermission.objects.filter(user=test_user, module='clients', action='create').update(is_allowed=False)
    has_create = test_user.has_permission('clients', 'create')
    print(f"   Client create permission after revoke (should be False): {has_create}")
    assert not has_create, "ERROR: User should NOT have client create permission after revoke!"
    
    # Test 2: Client Edit Permission
    print("\n3. Testing Client Edit Permission...")
    UserPermission.objects.filter(user=test_user, module='clients', action='edit').delete()
    has_edit = test_user.has_permission('clients', 'edit')
    print(f"   Client edit permission (should be False): {has_edit}")
    assert not has_edit, "ERROR: User should NOT have client edit permission!"
    
    # Test 3: Client Delete Permission
    print("\n4. Testing Client Delete Permission...")
    UserPermission.objects.filter(user=test_user, module='clients', action='delete').delete()
    has_delete = test_user.has_permission('clients', 'delete')
    print(f"   Client delete permission (should be False): {has_delete}")
    assert not has_delete, "ERROR: User should NOT have client delete permission!"
    
    # Test 4: Loan Create Permission
    print("\n5. Testing Loan Create Permission...")
    UserPermission.objects.filter(user=test_user, module='loans', action='create').delete()
    has_loan_create = test_user.has_permission('loans', 'create')
    print(f"   Loan create permission (should be False): {has_loan_create}")
    assert not has_loan_create, "ERROR: User should NOT have loan create permission!"
    
    # Test 5: Loan Approve Permission
    print("\n6. Testing Loan Approve Permission...")
    UserPermission.objects.filter(user=test_user, module='loans', action='approve').delete()
    has_loan_approve = test_user.has_permission('loans', 'approve')
    print(f"   Loan approve permission (should be False): {has_loan_approve}")
    assert not has_loan_approve, "ERROR: User should NOT have loan approve permission!"
    
    # Test 6: Test all SIMPLIFIED_PERMISSIONS
    print("\n7. Testing All Simplified Permissions...")
    from users.simplified_permissions_views import SIMPLIFIED_PERMISSIONS, get_module_code
    
    failed_permissions = []
    for module_name, actions in SIMPLIFIED_PERMISSIONS.items():
        module_code = get_module_code(module_name)
        for action_code, action_description in actions.items():
            # Clear permission
            UserPermission.objects.filter(user=test_user, module=module_code, action=action_code).delete()
            
            # Check it's denied
            has_perm = test_user.has_permission(module_code, action_code)
            if has_perm:
                # Check if it's from role default
                try:
                    role_perm = RolePermission.objects.get(
                        role=test_user.role,
                        module=module_code,
                        action=action_code
                    )
                    if role_perm.is_allowed:
                        # This is OK - role default allows it
                        pass
                    else:
                        failed_permissions.append(f"{module_code}.{action_code} - should be denied but role default allows")
                except RolePermission.DoesNotExist:
                    try:
                        default_perm = DefaultRolePermission.objects.get(
                            role=test_user.role,
                            module=module_code,
                            action=action_code
                        )
                        if default_perm.is_allowed:
                            # This is OK - default allows it
                            pass
                        else:
                            failed_permissions.append(f"{module_code}.{action_code} - should be denied but default allows")
                    except DefaultRolePermission.DoesNotExist:
                        # No default, should be denied
                        failed_permissions.append(f"{module_code}.{action_code} - should be denied but returned True")
            
            # Grant permission and verify
            UserPermission.objects.update_or_create(
                user=test_user,
                module=module_code,
                action=action_code,
                defaults={'is_allowed': True, 'granted_by': CustomUser.objects.filter(role='admin').first()}
            )
            has_perm = test_user.has_permission(module_code, action_code)
            if not has_perm:
                failed_permissions.append(f"{module_code}.{action_code} - should be allowed but returned False")
    
    if failed_permissions:
        print(f"\n   FAILED: {len(failed_permissions)} permissions not working correctly:")
        for perm in failed_permissions[:10]:
            print(f"     - {perm}")
        if len(failed_permissions) > 10:
            print(f"     ... and {len(failed_permissions) - 10} more")
    else:
        print("   All permissions working correctly!")
    
    print("\n" + "=" * 80)
    print("TEST SUMMARY")
    print("=" * 80)
    print(f"Total permissions tested: {sum(len(actions) for actions in SIMPLIFIED_PERMISSIONS.values())}")
    print(f"Failed permissions: {len(failed_permissions)}")
    
    if failed_permissions:
        print("\nACTION REQUIRED: Fix the failed permissions above")
        return False
    else:
        print("\nSUCCESS: All permissions are working correctly!")
        return True

if __name__ == '__main__':
    success = test_permission_enforcement()
    sys.exit(0 if success else 1)

