"""
Comprehensive test script to verify all permissions work correctly.
Creates sample staff members with different permission levels and tests all checkboxes.
"""
import os
import sys
import django

# Setup Django
sys.path.insert(0, 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 django.db import transaction
from users.models import CustomUser, RolePermission, UserPermission, DefaultRolePermission, Branch
from users.simplified_permissions_views import SIMPLIFIED_PERMISSIONS, get_module_code
from django.utils import timezone
import uuid

def create_branch_if_not_exists():
    """Create a test branch if it doesn't exist"""
    branch, created = Branch.objects.get_or_create(
        code='TEST',
        defaults={
            'name': 'Test Branch',
            'is_active': True,
            'is_main_branch': True
        }
    )
    return branch

def create_sample_users():
    """Create sample staff members with different roles"""
    branch = create_branch_if_not_exists()
    
    # Get or create admin user
    admin, created = CustomUser.objects.get_or_create(
        username='admin',
        defaults={
            'email': 'admin@test.com',
            'phone_number': '+254700000001',
            'first_name': 'Admin',
            'last_name': 'User',
            'role': 'admin',
            'status': 'active',
            'is_staff': True,
            'is_superuser': True,
            'branch': branch
        }
    )
    if created:
        admin.set_password('admin123')
        admin.save()
        print(f"[OK] Created admin user: {admin.username}")
    else:
        print(f"[OK] Admin user already exists: {admin.username}")
    
    # Create test users with different roles
    test_users = [
        {
            'username': 'loan_officer_full',
            'email': 'loanofficer@test.com',
            'phone_number': '+254700000002',
            'first_name': 'Loan',
            'last_name': 'Officer Full',
            'role': 'loan_officer',
            'description': 'Loan Officer with full permissions for testing'
        },
        {
            'username': 'loan_officer_limited',
            'email': 'loanofficer2@test.com',
            'phone_number': '+254700000003',
            'first_name': 'Loan',
            'last_name': 'Officer Limited',
            'role': 'loan_officer',
            'description': 'Loan Officer with limited permissions (read-only)'
        },
        {
            'username': 'team_leader',
            'email': 'teamleader@test.com',
            'phone_number': '+254700000004',
            'first_name': 'Team',
            'last_name': 'Leader',
            'role': 'team_leader',
            'description': 'Team Leader with selective permissions'
        },
        {
            'username': 'secretary',
            'email': 'secretary@test.com',
            'phone_number': '+254700000005',
            'first_name': 'Secretary',
            'last_name': 'User',
            'role': 'secretary',
            'description': 'Secretary with document and notification permissions'
        },
        {
            'username': 'auditor',
            'email': 'auditor@test.com',
            'phone_number': '+254700000006',
            'first_name': 'Auditor',
            'last_name': 'User',
            'role': 'auditor',
            'description': 'Auditor with read-only and audit permissions'
        },
    ]
    
    created_users = []
    for user_data in test_users:
        user, created = CustomUser.objects.get_or_create(
            username=user_data['username'],
            defaults={
                'email': user_data['email'],
                'phone_number': user_data['phone_number'],
                'first_name': user_data['first_name'],
                'last_name': user_data['last_name'],
                'role': user_data['role'],
                'status': 'active',
                'is_staff': True,
                'branch': branch
            }
        )
        if created:
            user.set_password('test123')
            user.save()
            print(f"[OK] Created {user_data['role']} user: {user.username} - {user_data['description']}")
        else:
            print(f"[OK] User already exists: {user.username}")
        created_users.append((user, user_data))
    
    return admin, created_users

def assign_permissions(user, permission_profile):
    """Assign permissions to a user based on a profile"""
    print(f"\n[ASSIGN] Assigning permissions to {user.username} ({user.role})...")
    
    with transaction.atomic():
        # Clear existing custom permissions
        UserPermission.objects.filter(user=user).delete()
        
        total_permissions = 0
        allowed_count = 0
        
        for module_name, actions in SIMPLIFIED_PERMISSIONS.items():
            module_code = get_module_code(module_name)
            
            for action_code, action_description in actions.items():
                total_permissions += 1
                
                # Determine if this permission should be allowed based on profile
                is_allowed = permission_profile(module_name, action_code, user.role)
                
                if is_allowed:
                    allowed_count += 1
                    # Only create custom permission if it differs from role default
                    try:
                        role_perm = RolePermission.objects.get(
                            role=user.role,
                            module=module_code,
                            action=action_code
                        )
                        role_default = role_perm.is_allowed
                    except RolePermission.DoesNotExist:
                        try:
                            default_perm = DefaultRolePermission.objects.get(
                                role=user.role,
                                module=module_code,
                                action=action_code
                            )
                            role_default = default_perm.is_allowed
                        except DefaultRolePermission.DoesNotExist:
                            role_default = False
                    
                    # Only create if different from role default
                    if is_allowed != role_default:
                        UserPermission.objects.create(
                            user=user,
                            module=module_code,
                            action=action_code,
                            is_allowed=is_allowed,
                            granted_by=CustomUser.objects.filter(role='admin').first(),
                            reason=f'Custom permission for {action_description}'
                        )
        
        print(f"   [OK] Assigned {allowed_count}/{total_permissions} permissions")
        return allowed_count, total_permissions

def profile_full_access(module_name, action_code, role):
    """Full access profile - all permissions allowed"""
    return True

def profile_read_only(module_name, action_code, role):
    """Read-only profile - only access, view, download, print allowed"""
    read_actions = {'access', 'download', 'print', 'monitor', 'audit'}
    return action_code in read_actions

def profile_selective(module_name, action_code, role):
    """Selective profile - access + common actions for team leader"""
    always_allowed = {'access', 'view', 'download', 'print', 'monitor'}
    
    # Team leaders can do most things except delete and critical system actions
    if action_code in {'delete', 'suspend', 'close', 'restore'}:
        return False
    
    # Settings modules are restricted
    if 'Settings' in module_name and action_code not in always_allowed:
        return False
    
    return action_code in always_allowed or action_code in {
        'create', 'edit', 'approve', 'verify', 'export', 'process', 
        'generate', 'record', 'assign', 'reassign', 'manage', 'send', 'email'
    }

def profile_secretary(module_name, action_code, role):
    """Secretary profile - document and notification focused"""
    always_allowed = {'access', 'view', 'download', 'print'}
    
    # Full access to documents and notifications
    if module_name in {'Documents', 'Customer Documents', 'Notifications'}:
        restricted_actions = {'delete', 'suspend', 'close'}
        return action_code not in restricted_actions
    
    # Limited access to other modules
    if module_name in {'Clients', 'Loans', 'Repayments'}:
        return action_code in always_allowed or action_code in {'create', 'record', 'generate', 'send', 'email'}
    
    # No access to settings
    if 'Settings' in module_name:
        return False
    
    return action_code in always_allowed

def profile_auditor(module_name, action_code, role):
    """Auditor profile - read-only with audit capabilities"""
    audit_actions = {'access', 'view', 'download', 'print', 'monitor', 'audit', 'export', 'generate'}
    
    # Can audit everything
    if action_code == 'audit':
        return True
    
    # Read-only for most modules
    if module_name not in {'Settings', 'Branch Settings', 'System Settings'}:
        return action_code in audit_actions
    
    # No access to settings
    return False

def verify_permissions(user):
    """Verify that permissions are correctly assigned and work"""
    print(f"\n[VERIFY] Verifying permissions for {user.username}...")
    
    verification_results = {
        'total_checked': 0,
        'correct': 0,
        'incorrect': 0,
        'issues': []
    }
    
    # Test a sample of permissions from each module
    test_permissions = [
        ('Dashboard', 'access'),
        ('Dashboard', 'create'),
        ('Clients', 'access'),
        ('Clients', 'create'),
        ('Clients', 'delete'),
        ('Loans', 'access'),
        ('Loans', 'approve'),
        ('Loans', 'delete'),
        ('Repayments', 'access'),
        ('Repayments', 'process'),
        ('Portfolio', 'access'),
        ('Portfolio', 'manage'),
        ('Reports & Statements', 'access'),
        ('Reports & Statements', 'generate'),
        ('Documents', 'access'),
        ('Documents', 'upload'),
        ('Documents', 'delete'),
        ('Customer Documents', 'access'),
        ('Customer Documents', 'upload'),
        ('Payment Receipts', 'access'),
        ('Payment Receipts', 'generate'),
        ('Notifications', 'access'),
        ('Notifications', 'send'),
        ('Settings', 'access'),
        ('Settings', 'edit'),
        ('Branch Settings', 'access'),
        ('Branch Settings', 'configure'),
        ('System Settings', 'access'),
        ('System Settings', 'manage'),
    ]
    
    for module_name, action_code in test_permissions:
        module_code = get_module_code(module_name)
        verification_results['total_checked'] += 1
        
        # Check permission
        has_perm = user.has_permission(module_code, action_code)
        
        # Check if it's a custom permission
        is_custom = UserPermission.objects.filter(
            user=user,
            module=module_code,
            action=action_code
        ).exists()
        
        # For admin, all should be True
        if user.role == 'admin':
            if not has_perm:
                verification_results['incorrect'] += 1
                verification_results['issues'].append(
                    f"[ERROR] Admin should have {module_name}.{action_code} but doesn't"
                )
            else:
                verification_results['correct'] += 1
        else:
            # For other users, just verify the check works
            status = "[OK]" if has_perm else "[DENIED]"
            source = "custom" if is_custom else "role/default"
            print(f"   {status} {module_name}.{action_code} ({source})")
            verification_results['correct'] += 1
    
    print(f"\n   Verification Summary:")
    print(f"   - Total checked: {verification_results['total_checked']}")
    print(f"   - Correct: {verification_results['correct']}")
    print(f"   - Issues: {len(verification_results['issues'])}")
    
    if verification_results['issues']:
        for issue in verification_results['issues']:
            print(f"   {issue}")
    
    return verification_results

def test_permission_enforcement(user):
    """Test that permissions actually prevent/allow access"""
    print(f"\n[TEST] Testing permission enforcement for {user.username}...")
    
    test_cases = [
        {
            'module': 'dashboard',
            'action': 'access',
            'description': 'Dashboard access'
        },
        {
            'module': 'clients',
            'action': 'create',
            'description': 'Create clients'
        },
        {
            'module': 'loans',
            'action': 'approve',
            'description': 'Approve loans'
        },
        {
            'module': 'settings',
            'action': 'edit',
            'description': 'Edit settings'
        },
    ]
    
    for test_case in test_cases:
        has_perm = user.has_permission(test_case['module'], test_case['action'])
        status = "[ALLOWED]" if has_perm else "[DENIED]"
        print(f"   {status} - {test_case['description']} ({test_case['module']}.{test_case['action']})")

def main():
    """Main test function"""
    print("=" * 80)
    print("COMPREHENSIVE PERMISSION TESTING")
    print("=" * 80)
    
    # Create sample users
    print("\n[STEP 1] Creating sample users...")
    admin, test_users = create_sample_users()
    
    # Assign different permission profiles
    print("\n[STEP 2] Assigning permission profiles...")
    profiles = {
        'loan_officer_full': profile_full_access,
        'loan_officer_limited': profile_read_only,
        'team_leader': profile_selective,
        'secretary': profile_secretary,
        'auditor': profile_auditor,
    }
    
    for user, user_data in test_users:
        profile_func = profiles.get(user.username)
        if profile_func:
            assign_permissions(user, profile_func)
    
    # Verify permissions
    print("\n[STEP 3] Verifying permissions...")
    for user, _ in test_users:
        verify_permissions(user)
        test_permission_enforcement(user)
    
    # Verify admin has all permissions
    print("\n[STEP 4] Verifying admin permissions...")
    verify_permissions(admin)
    test_permission_enforcement(admin)
    
    # Summary
    print("\n" + "=" * 80)
    print("TEST SUMMARY")
    print("=" * 80)
    print("\n[OK] Sample users created:")
    print(f"  - Admin: {admin.username} (password: admin123)")
    for user, user_data in test_users:
        print(f"  - {user_data['description']}: {user.username} (password: test123)")
    
    print("\n[OK] Permission profiles assigned:")
    print("  - loan_officer_full: Full access to all permissions")
    print("  - loan_officer_limited: Read-only access")
    print("  - team_leader: Selective access (no delete/critical actions)")
    print("  - secretary: Document and notification focused")
    print("  - auditor: Read-only with audit capabilities")
    
    print("\n[OK] Next steps:")
    print("  1. Log in as each test user and verify they can/cannot access features")
    print("  2. Check the simplified permissions page for each user")
    print("  3. Test that permission checks in views actually work")
    print("  4. Verify that UI elements are hidden/shown based on permissions")
    
    print("\n" + "=" * 80)

if __name__ == '__main__':
    main()

