from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required, user_passes_test
from .decorators import admin_required, staff_required, portfolio_access_required
from django.contrib import messages
from django.db.models import Q, Sum, Count
from django.db.models.functions import Coalesce
from django.http import JsonResponse, HttpResponseRedirect, HttpResponse
from django.core.paginator import Paginator
from django.utils import timezone
from utils.datetime_utils import get_current_datetime, make_datetime_compatible
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.forms import AuthenticationForm
from django.views.decorators.csrf import csrf_protect
from django.views.decorators.http import require_http_methods
from django.urls import reverse
from django.views.decorators.clickjacking import xframe_options_sameorigin
from utils.models import AuditLog, SystemSetting, Document, DocumentTag, DocumentShare, Notification, OfferLetter, Receipt, LoanStatement
from utils.reports import OptimizedReportGenerator as ReportGenerator
from loans.models import Loan, LoanApplication, Repayment, RolloverRequest
from users.models import CustomUser, Branch
from reports.models import LoanScoring
from django.db import transaction
from .decorators import admin_required, staff_required, portfolio_access_required
from utils.filtering import (
    apply_branch_and_portfolio_filters,
    get_filtered_clients
)
import json


@login_required
def filtered_clients(request):
    """View for filtered clients based on status"""
    status = request.GET.get('status', 'active')
    selected_branch_id = request.session.get('selected_branch_id')
    
    # Base queryset for borrowers
    clients_qs = CustomUser.objects.filter(role='borrower')
    
    # Apply portfolio-based access control for staff members
    if request.user.role in ['loan_officer', 'team_leader'] and not request.user.is_superuser:
        # Staff members can only see their assigned borrowers
        clients_qs = clients_qs.filter(portfolio_manager=request.user)
    elif request.user.role in ['secretary', 'auditor'] and not request.user.is_superuser:
        # Secretaries and auditors can only see borrowers from their branch
        if request.user.branch:
            clients_qs = clients_qs.filter(branch=request.user.branch)
    
    # Apply branch filtering if a branch is selected
    if selected_branch_id:
        clients_qs = clients_qs.filter(branch_id=selected_branch_id)
    
    # Apply status filtering
    if status == 'active':
        clients_qs = clients_qs.filter(is_active=True)
    elif status == 'inactive':
        clients_qs = clients_qs.filter(is_active=False)
    elif status == 'blacklisted':
        clients_qs = clients_qs.filter(status='blacklisted')
    elif status == 'with_loans':
        clients_qs = clients_qs.filter(loans__isnull=False).distinct()
    elif status == 'without_loans':
        clients_qs = clients_qs.filter(loans__isnull=True)
    elif status == 'assigned':
        clients_qs = clients_qs.filter(portfolio_manager__isnull=False)
    elif status == 'unassigned':
        clients_qs = clients_qs.filter(portfolio_manager__isnull=True)
    elif status == 'new_this_month':
        from datetime import datetime
        current_month = datetime.now().replace(day=1, hour=0, minute=0, second=0, microsecond=0)
        clients_qs = clients_qs.filter(date_joined__gte=current_month)
    elif status == 'all':
        pass  # No additional filtering for 'all'
    
    # Order by most recent
    clients_qs = clients_qs.order_by('-date_joined')
    
    # Add loan statistics with fixed output_field for mixed types
    from django.db.models import DecimalField, IntegerField
    
    clients_qs = clients_qs.annotate(
        total_loans=Count('loans', output_field=IntegerField()),
        active_loans=Count('loans', filter=Q(loans__status__in=['active', 'rolled_over']), output_field=IntegerField()),
        total_borrowed=Coalesce(Sum('loans__principal_amount', output_field=DecimalField()), 0, output_field=DecimalField())
    )
    
    # Pagination
    paginator = Paginator(clients_qs, 25)
    page = request.GET.get('page')
    try:
        clients = paginator.page(page)
    except:
        clients = paginator.page(1)
    
    context = {
        'clients': clients,
        'status_filter': status,
        'title': f'{status.replace("_", " ").title()} Clients',
        'total_count': clients_qs.count(),
    }
    
    return render(request, 'users/filtered_clients.html', context)


def safe_delete_user_records(user):
    """
    Safely delete all user-related records with proper error handling
    This function handles different database schema variations
    """
    from django.db import connection, transaction
    from django.contrib import messages
    import logging
    
    logger = logging.getLogger(__name__)
    deletion_log = []
    
    try:
        with transaction.atomic():
            # Get all table names and their columns
            with connection.cursor() as cursor:
                # Check what tables exist and their user reference columns
                tables_to_check = [
                    ('loan_statements', ['borrower_id', 'user_id', 'client_id']),
                    ('receipts', ['borrower_id', 'user_id', 'client_id']),
                    ('offer_letters', ['borrower_id', 'user_id', 'client_id']),
                    ('rollover_requests', ['borrower_id', 'user_id', 'client_id']),
                    ('loan_scoring', ['user_id', 'borrower_id', 'client_id']),
                    ('utils_notification', ['user_id', 'recipient_id']),
                    ('utils_document', ['uploaded_by_id', 'user_id']),
                    ('utils_documentshare', ['shared_with_id', 'user_id']),
                    ('loans', ['borrower_id', 'user_id', 'client_id']),
                ]
                
                for table_name, possible_columns in tables_to_check:
                    try:
                        # Check if table exists
                        cursor.execute(f"""
                            SELECT COUNT(*) 
                            FROM INFORMATION_SCHEMA.TABLES 
                            WHERE TABLE_SCHEMA = DATABASE() 
                            AND TABLE_NAME = '{table_name}'
                        """)
                        
                        if cursor.fetchone()[0] == 0:
                            deletion_log.append(f"Table {table_name} does not exist - skipping")
                            continue
                        
                        # Find which column exists
                        user_column = None
                        for col in possible_columns:
                            cursor.execute(f"""
                                SELECT COUNT(*) 
                                FROM INFORMATION_SCHEMA.COLUMNS 
                                WHERE TABLE_SCHEMA = DATABASE() 
                                AND TABLE_NAME = '{table_name}' 
                                AND COLUMN_NAME = '{col}'
                            """)
                            
                            if cursor.fetchone()[0] > 0:
                                user_column = col
                                break
                        
                        if user_column:
                            # Delete records using the found column
                            cursor.execute(f"""
                                DELETE FROM {table_name} 
                                WHERE {user_column} = %s
                            """, [str(user.id)])
                            
                            deleted_count = cursor.rowcount
                            deletion_log.append(f"Deleted {deleted_count} records from {table_name} using {user_column}")
                        else:
                            deletion_log.append(f"No user reference column found in {table_name}")
                            
                    except Exception as e:
                        deletion_log.append(f"Error processing {table_name}: {str(e)}")
                        logger.error(f"Error deleting from {table_name}: {e}")
                
                # Finally delete the user
                user.delete()
                deletion_log.append(f"Successfully deleted user: {user.email}")
                
        return True, deletion_log
        
    except Exception as e:
        logger.error(f"Critical error during user deletion: {e}")
        return False, [f"Critical error: {str(e)}"] + deletion_log


# Import portfolio views
from .portfolio_views import (
    portfolio_dashboard, portfolio_manager_detail, assign_clients,
    portfolio_analytics, reassign_client, bulk_assign_clients,
    portfolio_performance_api
)
from PIL import Image
from io import BytesIO
from django.core.files.base import ContentFile

# Try to import magic, but make it optional
try:
    import magic
    MAGIC_AVAILABLE = True
except (ImportError, OSError):
    MAGIC_AVAILABLE = False
    magic = None

from utils.models import Notification
from loans.models import Repayment


def invalidate_client_popup_cache(client_id):
    """Invalidate cached client popup data when client is updated"""
    from django.core.cache import cache
    cache_key = f'client_popup_{client_id}'
    cache.delete(cache_key)
    print(f"Invalidated cache for client popup: {cache_key}")


def get_client_dependencies(client):
    """Get all dependencies for a client to display before deletion"""
    dependencies = {}
    
    try:
        # Loans
        dependencies['loans'] = Loan.objects.filter(borrower=client).count()
        
        # Loan Applications
        dependencies['applications'] = LoanApplication.objects.filter(borrower=client).count()
        
        # Repayments (through loans)
        loan_ids = list(Loan.objects.filter(borrower=client).values_list('id', flat=True))
        dependencies['repayments'] = Repayment.objects.filter(loan_id__in=loan_ids).count()
        
        # Rollover Requests
        dependencies['rollover_requests'] = RolloverRequest.objects.filter(borrower=client).count()
        
        # Utils models
        dependencies['offers'] = OfferLetter.objects.filter(borrower=client).count()
        dependencies['receipts'] = Receipt.objects.filter(borrower=client).count()
        dependencies['statements'] = LoanStatement.objects.filter(borrower=client).count()
        dependencies['notifications'] = Notification.objects.filter(user=client).count()
        
        # Documents
        dependencies['documents'] = Document.objects.filter(uploaded_by=client).count()
        dependencies['document_shares'] = DocumentShare.objects.filter(shared_with=client).count()
        
        # Reports
        try:
            dependencies['scoring_records'] = LoanScoring.objects.filter(borrower=client).count()
        except:
            dependencies['scoring_records'] = 0
        
        # Audit logs
        dependencies['audit_logs'] = AuditLog.objects.filter(user=client).count()
        
        # Calculate total
        dependencies['total'] = sum(dependencies.values())
        
    except Exception as e:
        print(f"Error getting dependencies: {e}")
        dependencies = {'total': 0, 'error': str(e)}
    
    return dependencies


def safe_delete_client_permanently(client, user):
    """Safely delete a client with all dependencies"""
    try:
        with transaction.atomic():
            client_name = client.get_full_name()
            client_id = client.id
            
            # Delete in correct order to avoid foreign key constraints
            
            # 1. Delete receipts first (they reference repayments and loans)
            Receipt.objects.filter(borrower=client).delete()
            
            # 2. Delete loan statements
            LoanStatement.objects.filter(borrower=client).delete()
            
            # 3. Delete loan offers
            OfferLetter.objects.filter(borrower=client).delete()
            
            # 4. Delete rollover requests
            from loans.models import RolloverRequest
            RolloverRequest.objects.filter(borrower=client).delete()
            
            # 5. Delete repayments (through loans)
            loan_ids = list(Loan.objects.filter(borrower=client).values_list('id', flat=True))
            Repayment.objects.filter(loan_id__in=loan_ids).delete()
            
            # 6. Delete loans
            Loan.objects.filter(borrower=client).delete()
            
            # 7. Delete loan applications
            LoanApplication.objects.filter(borrower=client).delete()
            
            # 8. Delete scoring records
            try:
                from reports.models import LoanScoring
                LoanScoring.objects.filter(user=client).delete()
            except:
                pass
            
            # 9. Delete document shares
            DocumentShare.objects.filter(shared_with=client).delete()
            
            # 10. Delete documents and their files
            documents = Document.objects.filter(uploaded_by=client)
            for doc in documents:
                try:
                    if doc.file and hasattr(doc.file, 'path'):
                        import os
                        if os.path.exists(doc.file.path):
                            os.remove(doc.file.path)
                except:
                    pass
            documents.delete()
            
            # 11. Delete notifications
            Notification.objects.filter(user=client).delete()
            
            # 11.5. Delete portfolio performance records if they exist
            try:
                # Only delete portfolio performance records if the user being deleted 
                # is actually a portfolio manager
                if client.role in ['loan_officer', 'team_leader']:
                    from users.models import PortfolioPerformance
                    PortfolioPerformance.objects.filter(portfolio_manager=client).delete()
            except Exception as e:
                # Log but don't fail the deletion
                pass
            
            # 12. Update audit logs (don't delete, just anonymize)
            AuditLog.objects.filter(user=client).update(user=None)
            
            # 13. Invalidate cache
            invalidate_client_popup_cache(client_id)
            
            # 14. Finally delete the client
            client.delete()
            
            # Create final audit log
            AuditLog.objects.create(
                user=user,
                action='delete',
                model_name='CustomUser',
                object_id=str(client_id),
                description=f'Permanently deleted client: {client_name} and all related data'
            )
            
            return True, f'Client {client_name} and all related data have been permanently deleted successfully'
            
    except Exception as e:
        return False, f'Error during deletion: {str(e)}'

@csrf_protect
@require_http_methods(["GET", "POST"])
def custom_login(request):
    """
    Custom login view with enhanced security and email-based authentication
    """
    # Redirect if user is already authenticated
    if request.user.is_authenticated:
        return HttpResponseRedirect(reverse('dashboard'))
    
    if request.method == 'POST':
        # Get credentials from POST data
        username = request.POST.get('username')
        password = request.POST.get('password')
        
        # Try to authenticate
        user = authenticate(request, username=username, password=password)
        
        if user is not None:
            # Check if user is active and not suspended
            if user.is_active and user.status != 'suspended':
                login(request, user)
                
                # Update last login time
                user.last_login_at = get_current_datetime()
                user.save()
                
                # Create audit log
                AuditLog.objects.create(
                    user=user,
                    action='login',
                    model_name='CustomUser',
                    object_id=str(user.id),
                    description=f'User logged in via email: {username}',
                    ip_address=request.META.get('REMOTE_ADDR'),
                    user_agent=request.META.get('HTTP_USER_AGENT', '')
                )
                
                # Redirect to main dashboard
                return HttpResponseRedirect(reverse('dashboard'))
            else:
                messages.error(request, 'Your account has been suspended. Please contact support.')
        else:
            messages.error(request, 'Invalid email or password. Please try again.')
        
        # If we get here, authentication failed - just re-render the form
    
    # GET request or failed POST
    return render(request, 'users/login.html', {
        'form': AuthenticationForm()
    })


@login_required
def custom_logout(request):
    """Custom logout view"""
    # Create audit log
    AuditLog.objects.create(
        user=request.user,
        action='logout',
        model_name='CustomUser',
        object_id=str(request.user.id),
        description=f'User logged out: {request.user.get_full_name()}'
    )
    
    # Perform logout
    logout(request)
    messages.success(request, 'You have been logged out successfully')
    return redirect('users:login')


@login_required
@portfolio_access_required
def client_list(request):
    """List all clients with filtering and search"""
    # Check if user has permission to access clients
    if not request.user.has_permission('clients', 'access'):
        messages.error(request, 'You do not have permission to view clients.')
        return redirect('dashboard')
    
    try:
        # Get selected branch from session
        selected_branch_id = request.session.get('selected_branch_id')
        
        # Ensure branch selection is always available
        if not selected_branch_id and request.user.is_authenticated:
            if request.user.is_staff:
                # For staff users, default to main branch if no selection
                main_branch = Branch.objects.filter(is_main_branch=True, is_active=True).first()
                if main_branch:
                    selected_branch_id = str(main_branch.id)
                    request.session['selected_branch_id'] = selected_branch_id
            elif request.user.branch:
                # For non-staff users, use their assigned branch
                selected_branch_id = str(request.user.branch.id)
                request.session['selected_branch_id'] = selected_branch_id
        
        # Get filter parameters
        search = request.GET.get('search', '')
        status_filter = request.GET.get('status', '')
        business_type_filter = request.GET.get('business_type', '')
        date_from = request.GET.get('date_from', '')
        date_to = request.GET.get('date_to', '')
        sort_by = request.GET.get('sort_by', 'first_name')  # Default sort by first name
        sort_order = request.GET.get('sort_order', 'asc')   # Default ascending order
        
        # Base queryset with branch filtering
        # Only show APPROVED clients - explicitly exclude rejected and pending
        clients = CustomUser.objects.filter(
            role='borrower'
        ).exclude(
            # Exclude any client with rejection information (OR condition)
            Q(rejected_at__isnull=False) | Q(rejected_by__isnull=False) | Q(status='pending_approval') | Q(status='inactive')
        ).filter(
            status='active',  # Only active/approved clients
            is_active=True  # Must be active
        ).select_related()
        
        # Apply portfolio-based access control for staff members
        if request.user.role in ['loan_officer', 'team_leader'] and not request.user.is_superuser:
            # Staff members can only see their assigned borrowers
            clients = clients.filter(portfolio_manager=request.user)
        elif request.user.role in ['secretary', 'auditor'] and not request.user.is_superuser:
            # Secretaries and auditors can only see borrowers from their branch
            if request.user.branch:
                clients = clients.filter(branch=request.user.branch)
        
        # Apply branch filtering - now always has a branch selected
        if selected_branch_id:
            clients = clients.filter(branch_id=selected_branch_id)
        # No branch selected — show all clients regardless of branch assignment
        
        # Apply filters
        if search:
            clients = clients.filter(
                Q(first_name__icontains=search) |
                Q(last_name__icontains=search) |
                Q(business_name__icontains=search) |
                Q(id_number__icontains=search) |
                Q(phone_number__icontains=search) |
                Q(email__icontains=search)
            )
        
        # Apply status filter if provided - but never override the active/rejected exclusions
        if status_filter:
            # Don't allow filtering to show inactive or rejected clients
            if status_filter not in ['inactive', 'pending_approval']:
                clients = clients.filter(status=status_filter)
        
        if business_type_filter:
            clients = clients.filter(business_type=business_type_filter)
        
        # Apply date range filtering
        if date_from:
            try:
                from datetime import datetime
                date_from_obj = datetime.strptime(date_from, '%Y-%m-%d').date()
                clients = clients.filter(date_joined__date__gte=date_from_obj)
            except (ValueError, TypeError):
                pass  # Invalid date format, ignore
        
        if date_to:
            try:
                from datetime import datetime
                date_to_obj = datetime.strptime(date_to, '%Y-%m-%d').date()
                clients = clients.filter(date_joined__date__lte=date_to_obj)
            except (ValueError, TypeError):
                pass  # Invalid date format, ignore
        
        # Apply sorting
        if sort_by == 'first_name':
            if sort_order == 'desc':
                clients = clients.order_by('-first_name', '-last_name')
            else:
                clients = clients.order_by('first_name', 'last_name')
        elif sort_by == 'last_name':
            if sort_order == 'desc':
                clients = clients.order_by('-last_name', '-first_name')
            else:
                clients = clients.order_by('last_name', 'first_name')
        elif sort_by == 'business_name':
            if sort_order == 'desc':
                clients = clients.order_by('-business_name')
            else:
                clients = clients.order_by('business_name')
        elif sort_by == 'status':
            if sort_order == 'desc':
                clients = clients.order_by('-status')
            else:
                clients = clients.order_by('status')
        elif sort_by == 'created_at':
            if sort_order == 'desc':
                clients = clients.order_by('-created_at')
            else:
                clients = clients.order_by('created_at')
        elif sort_by == 'date_joined':
            if sort_order == 'desc':
                clients = clients.order_by('-date_joined')
            else:
                clients = clients.order_by('date_joined')
        elif sort_by == 'total_borrowed':
            # Sort by total borrowed amount (requires annotation)
            # Q, Sum, Count, and Loan are already imported at the top
            clients = clients.annotate(
                total_borrowed_amount=Sum('loan__principal_amount')
            )
            if sort_order == 'desc':
                clients = clients.order_by('-total_borrowed_amount', 'first_name')
            else:
                clients = clients.order_by('total_borrowed_amount', 'first_name')
        elif sort_by == 'total_repaid':
            # Sort by total repaid amount (requires annotation)
            # Q, Sum, Count, and Loan are already imported at the top
            # Note: Cannot annotate amount_paid as it's a property, not a field
            # Will calculate per-client in the loop below
            pass
            if sort_order == 'desc':
                clients = clients.order_by('-total_repaid_amount', 'first_name')
            else:
                clients = clients.order_by('total_repaid_amount', 'first_name')
        elif sort_by == 'active_loans':
            # Sort by number of active loans (requires annotation)
            # Q, Sum, Count, and Loan are already imported at the top
            clients = clients.annotate(
                active_loans_count=Count('loan', filter=Q(loan__status='active'))
            )
            if sort_order == 'desc':
                clients = clients.order_by('-active_loans_count', 'first_name')
            else:
                clients = clients.order_by('active_loans_count', 'first_name')
        elif sort_by == 'monthly_income':
            if sort_order == 'desc':
                clients = clients.order_by('-monthly_income', 'first_name')
            else:
                clients = clients.order_by('monthly_income', 'first_name')
        else:
            # Default sorting by first name ascending
            clients = clients.order_by('first_name', 'last_name')
        
        # Get loan statistics for each client
        # If we already annotated these fields for sorting, use them
        for client in clients:
            try:
                # Check if annotations were added during sorting
                if hasattr(client, 'total_borrowed_amount'):
                    client.total_borrowed = client.total_borrowed_amount or 0
                else:
                    client.total_borrowed = Loan.objects.filter(borrower=client).aggregate(
                        total=Sum('principal_amount')
                    )['total'] or 0
                
                # Calculate total repaid from repayments
                client.total_repaid = Repayment.objects.filter(
                    loan__borrower=client
                ).aggregate(total=Sum('amount'))['total'] or 0
                
                if hasattr(client, 'active_loans_count'):
                    client.active_loans = client.active_loans_count or 0
                else:
                    client.active_loans = Loan.objects.filter(borrower=client, status='active').count()
                
                # Get credit score
                try:
                    credit_score = LoanScoring.objects.get(user=client)
                    client.credit_score = credit_score.total_score
                except LoanScoring.DoesNotExist:
                    client.credit_score = 0
            except Exception as e:
                # Handle individual client errors
                client.active_loans = 0
                client.total_borrowed = 0
                client.total_repaid = 0
                client.credit_score = 0
                print(f"Error processing client {client.id}: {str(e)}")
        
        # Pagination
        paginator = Paginator(clients, 10)
        page_number = request.GET.get('page')
        page_obj = paginator.get_page(page_number)
        
        # Calculate client growth statistics
        from datetime import datetime, timedelta
        from django.utils import timezone
        
        today = timezone.now().date()
        thirty_days_ago = today - timedelta(days=30)
        sixty_days_ago = today - timedelta(days=60)
        ninety_days_ago = today - timedelta(days=90)
        
        # Get client counts for growth calculation
        all_clients_count = clients.count()
        clients_30_days = clients.filter(date_joined__date__gte=thirty_days_ago).count()
        clients_60_days = clients.filter(date_joined__date__gte=sixty_days_ago).count()
        clients_90_days = clients.filter(date_joined__date__gte=ninety_days_ago).count()
        
        # Calculate growth rates
        growth_30_days = clients_30_days
        growth_60_days = clients_60_days - clients_30_days
        growth_90_days = clients_90_days - clients_60_days
        
        # Calculate growth rate percentage (month-over-month)
        # Compare: Period 1 (0-30 days) vs Period 2 (30-60 days ago)
        # Period 1 = clients_30_days (last 30 days)
        # Period 2 = growth_60_days (clients between 30-60 days ago, which is clients_60_days - clients_30_days)
        growth_rate_percentage = None  # Use None to indicate "not calculable"
        growth_rate_display = None
        growth_rate_label = ""
        
        if clients_30_days > 0 and growth_60_days >= 0:
            # Normal case: Calculate percentage growth
            growth_rate_percentage = round((growth_60_days / clients_30_days) * 100, 1)
            growth_rate_display = 'percentage'
            growth_rate_label = "Month-over-month"
        elif clients_30_days > 0 and growth_60_days < 0:
            # Negative growth (decline)
            growth_rate_percentage = round((growth_60_days / clients_30_days) * 100, 1)
            growth_rate_display = 'negative'
            growth_rate_label = "Month-over-month decline"
        elif clients_30_days == 0 and clients_60_days > 0:
            # Special case: No clients in last 30 days but some in last 60 days
            # This means all growth happened in the 30-60 day period
            # Show the actual number of clients from that period instead
            growth_rate_percentage = growth_60_days
            growth_rate_display = 'recent_period'
            growth_rate_label = f"{growth_60_days} clients (30-60 days ago)"
        elif clients_30_days == 0 and growth_60_days == 0:
            # No clients in either period
            growth_rate_display = 'no_data'
            growth_rate_label = "No recent registrations"
        else:
            # Default: insufficient data
            growth_rate_display = 'insufficient'
            growth_rate_label = "Need more data"
        
        context = {
            'clients': page_obj,
            'search': search,
            'status_filter': status_filter,
            'business_type_filter': business_type_filter,
            'date_from': date_from,
            'date_to': date_to,
            'sort_by': sort_by,
            'sort_order': sort_order,
            'total_clients': all_clients_count,
            'selected_branch_id': selected_branch_id,  # Add this for template reference
            'clients_30_days': clients_30_days,
            'clients_60_days': clients_60_days,
            'clients_90_days': clients_90_days,
            'growth_30_days': growth_30_days,
            'growth_60_days': growth_60_days,
            'growth_90_days': growth_90_days,
            'growth_rate_percentage': growth_rate_percentage,
            'growth_rate_display': growth_rate_display,
            'growth_rate_label': growth_rate_label,
        }
        
        return render(request, 'users/client_list.html', context)
        
    except Exception as e:
        # Log the error and return a simple error page
        print(f"Error in client_list view: {str(e)}")
        return render(request, 'users/client_list.html', {
            'clients': [],
            'search': '',
            'status_filter': 'all',
            'business_type_filter': 'all',
            'sort_by': 'first_name',
            'sort_order': 'asc',
            'total_clients': 0,
            'error_message': f'An error occurred while loading clients: {str(e)}'
        })


@login_required
def client_list_test(request):
    """Simple test view for client list debugging"""
    try:
        clients = CustomUser.objects.filter(role='borrower')[:5]  # Just get first 5 clients
        
        # Simple data without complex queries
        for client in clients:
            client.active_loans = 0
            client.total_borrowed = 0
            client.total_repaid = 0
            client.credit_score = 0
        
        context = {
            'clients': clients,
            'search': '',
            'status_filter': 'all',
            'business_type_filter': 'all',
            'total_clients': clients.count(),
        }
        
        return render(request, 'users/client_list.html', context)
        
    except Exception as e:
        print(f"Error in test view: {str(e)}")
        return render(request, 'users/client_list.html', {
            'clients': [],
            'search': '',
            'status_filter': 'all',
            'business_type_filter': 'all',
            'total_clients': 0,
            'error_message': f'Test error: {str(e)}'
        })


@login_required
def client_detail(request, client_id):
    """Enhanced view for client details with comprehensive loan and payment information"""
    # Check if user has permission to access clients
    if not request.user.has_permission('clients', 'access'):
        messages.error(request, 'You do not have permission to view client details.')
        return redirect('users:client_list')
    
    client = get_object_or_404(CustomUser, id=client_id)
    
    # Check permissions
    if not request.user.is_staff and request.user != client:
        messages.error(request, 'You do not have permission to view this client')
        return redirect('users:client_list')
    
    # Get document counts
    documents = Document.objects.filter(uploaded_by=client)
    
    # Get loan history with enhanced data
    loans = Loan.objects.filter(borrower=client).select_related('application__loan_product').order_by('-created_at')
    applications = LoanApplication.objects.filter(borrower=client).select_related('loan_product').order_by('-submitted_at')
    
    # Get recent repayments
    recent_repayments = Repayment.objects.filter(
        loan__borrower=client
    ).select_related('loan').order_by('-payment_date')[:10]
    
    # Get credit score
    try:
        credit_score = LoanScoring.objects.get(user=client)
    except LoanScoring.DoesNotExist:
        credit_score = None
    
    # Calculate enhanced statistics
    total_borrowed = loans.aggregate(total=Sum('principal_amount'))['total'] or 0
    # Calculate total repaid from repayments instead of non-existent field
    total_repaid = Repayment.objects.filter(loan__borrower=client).aggregate(total=Sum('amount'))['total'] or 0
    total_outstanding = sum(loan.outstanding_amount for loan in loans.filter(status__in=['active', 'rolled_over']))
    
    # Loan status counts
    active_loans = loans.filter(status='active').count()
    paid_loans = loans.filter(status='paid').count()
    defaulted_loans = loans.filter(status='defaulted').count()
    rolled_over_loans = loans.filter(status='rolled_over').count()
    
    # Overdue loans
    overdue_loans = [loan for loan in loans.filter(status='active') if loan.is_overdue]
    overdue_count = len(overdue_loans)
    total_overdue_amount = sum(loan.outstanding_amount for loan in overdue_loans)
    
    # Payment history summary
    total_payments = recent_repayments.count()
    last_payment = recent_repayments.first()
    
    # Calculate payment performance
    if loans.exists():
        on_time_payments = 0
        total_due_dates = 0
        for loan in loans:
            if loan.status == 'paid' and not loan.is_overdue:
                on_time_payments += 1
            total_due_dates += 1
        
        payment_performance = (on_time_payments / total_due_dates * 100) if total_due_dates > 0 else 0
    else:
        payment_performance = 0
    
    # Get available loan products for new applications
    from loans.models import LoanProduct
    available_products = LoanProduct.objects.filter(is_active=True).order_by('name')
    
    context = {
        'client': client,
        'id_documents': documents.filter(document_type='id_document'),
        'selfie_documents': documents.filter(document_type='selfie'),
        'utility_documents': documents.filter(document_type='utility_bill'),
        'bank_documents': documents.filter(document_type='bank_statement'),
        'loans': loans[:20],  # Limit to recent 20 loans for performance
        'applications': applications[:10],  # Recent 10 applications
        'recent_repayments': recent_repayments,
        'credit_score': credit_score,
        'total_borrowed': total_borrowed,
        'total_repaid': total_repaid,
        'total_outstanding': total_outstanding,
        'active_loans': active_loans,
        'paid_loans': paid_loans,
        'defaulted_loans': defaulted_loans,
        'rolled_over_loans': rolled_over_loans,
        'overdue_count': overdue_count,
        'total_overdue_amount': total_overdue_amount,
        'last_payment': last_payment,
        'payment_performance': payment_performance,
        'available_products': available_products,
    }
    
    return render(request, 'users/client_detail.html', context)


@login_required
@staff_required
def client_complete_history(request, client_id):
    """Comprehensive client history page with all loans, applications, and payments"""
    client = get_object_or_404(CustomUser, id=client_id)
    
    # Get all loan applications
    applications = LoanApplication.objects.filter(
        borrower=client
    ).select_related('loan_product', 'reviewed_by').order_by('-submitted_at')
    
    # Get all loans
    loans = Loan.objects.filter(
        borrower=client
    ).select_related('application__loan_product').order_by('-created_at')
    
    # Get all repayments
    repayments = Repayment.objects.filter(
        loan__borrower=client
    ).select_related('loan').order_by('-payment_date')
    
    # Get documents (both uploaded by client and shared with client)
    from django.db.models import Q
    documents_queryset = Document.objects.filter(
        Q(uploaded_by=client) | Q(shared_with=client)
    ).select_related('uploaded_by').prefetch_related('tags').order_by('-created_at')
    
    # Convert to list and add client's direct file uploads as document objects
    documents = list(documents_queryset)
    
    # Add client's KYC documents as pseudo-document objects for display
    kyc_documents = []
    if client.id_document:
        kyc_documents.append({
            'document_type': 'id_document',
            'file': client.id_document,
            'uploaded_at': client.date_joined,
            'description': 'National ID Document',
            'status': 'approved' if client.is_verified else 'pending',
            'get_document_type_display': lambda: 'ID Document',
            'get_status_display': lambda: 'Approved' if client.is_verified else 'Pending'
        })
    
    if client.selfie:
        kyc_documents.append({
            'document_type': 'selfie',
            'file': client.selfie,
            'uploaded_at': client.date_joined,
            'description': 'Client Selfie Photo',
            'status': 'approved' if client.is_verified else 'pending',
            'get_document_type_display': lambda: 'Selfie Photo',
            'get_status_display': lambda: 'Approved' if client.is_verified else 'Pending'
        })
    
    if client.utility_bill:
        kyc_documents.append({
            'document_type': 'utility_bill',
            'file': client.utility_bill,
            'uploaded_at': client.date_joined,
            'description': 'Utility Bill',
            'status': 'approved' if client.is_verified else 'pending',
            'get_document_type_display': lambda: 'Utility Bill',
            'get_status_display': lambda: 'Approved' if client.is_verified else 'Pending'
        })
    
    if client.bank_statement:
        kyc_documents.append({
            'document_type': 'bank_statement',
            'file': client.bank_statement,
            'uploaded_at': client.date_joined,
            'description': 'Bank Statement',
            'status': 'approved' if client.is_verified else 'pending',
            'get_document_type_display': lambda: 'Bank Statement',
            'get_status_display': lambda: 'Approved' if client.is_verified else 'Pending'
        })
    
    if client.business_license:
        kyc_documents.append({
            'document_type': 'business_license',
            'file': client.business_license,
            'uploaded_at': client.date_joined,
            'description': 'Business License',
            'status': 'approved' if client.is_verified else 'pending',
            'get_document_type_display': lambda: 'Business License',
            'get_status_display': lambda: 'Approved' if client.is_verified else 'Pending'
        })
    
    # Combine both types of documents
    all_documents = kyc_documents + documents
    
    # Calculate comprehensive statistics
    total_applications = applications.count()
    approved_applications = applications.filter(status='approved').count()
    rejected_applications = applications.filter(status='rejected').count()
    pending_applications = applications.filter(status='pending').count()
    
    total_loans = loans.count()
    active_loans = loans.filter(status='active').count()
    paid_loans = loans.filter(status='paid').count()
    defaulted_loans = loans.filter(status='defaulted').count()
    
    total_borrowed = loans.aggregate(total=Sum('principal_amount'))['total'] or 0
    total_repaid = repayments.aggregate(total=Sum('amount'))['total'] or 0
    total_outstanding = sum(loan.outstanding_amount for loan in loans.filter(status__in=['active', 'rolled_over']))
    
    # Payment statistics
    total_payments = repayments.count()
    last_payment = repayments.first()
    
    # Overdue information
    overdue_loans = [loan for loan in loans.filter(status='active') if loan.is_overdue]
    overdue_count = len(overdue_loans)
    total_overdue_amount = sum(loan.outstanding_amount for loan in overdue_loans)
    
    # Credit score
    try:
        from reports.models import LoanScoring
        credit_score = LoanScoring.objects.get(user=client)
    except:
        credit_score = None
    
    # Timeline data (recent 50 activities)
    timeline_activities = []
    
    # Add applications to timeline (only show application submission)
    for app in applications[:20]:
        timeline_activities.append({
            'type': 'application',
            'date': app.submitted_at,
            'title': f'Applied for {app.loan_product.name}',
            'description': f'KES {app.requested_amount:,.2f} for {app.requested_duration} days',
            'status': app.status,
            'object': app
        })
    
    # Add loan disbursements to timeline
    for loan in loans[:20]:
        # Add disbursement event
        timeline_activities.append({
            'type': 'loan',
            'date': loan.disbursement_date,
            'title': f'Loan Disbursed - {loan.loan_number}',
            'description': f'KES {loan.principal_amount:,.2f}',
            'status': loan.status,
            'object': loan
        })
    
    # Add payments to timeline
    for payment in repayments[:30]:
        timeline_activities.append({
            'type': 'payment',
            'date': payment.payment_date,
            'title': f'Payment Received - {payment.receipt_number}',
            'description': f'KES {payment.amount:,.2f} via {payment.get_payment_method_display()}',
            'status': 'completed',
            'object': payment
        })
    
    # Sort timeline by date (most recent first)
    timeline_activities.sort(key=lambda x: x['date'], reverse=True)
    timeline_activities = timeline_activities[:50]  # Limit to 50 most recent
    
    context = {
        'client': client,
        'applications': applications,
        'loans': loans,
        'repayments': repayments,
        'documents': all_documents,
        'credit_score': credit_score,
        
        # Statistics
        'total_applications': total_applications,
        'approved_applications': approved_applications,
        'rejected_applications': rejected_applications,
        'pending_applications': pending_applications,
        'total_loans': total_loans,
        'active_loans': active_loans,
        'paid_loans': paid_loans,
        'defaulted_loans': defaulted_loans,
        'total_borrowed': total_borrowed,
        'total_repaid': total_repaid,
        'total_outstanding': total_outstanding,
        'total_payments': total_payments,
        'last_payment': last_payment,
        'overdue_count': overdue_count,
        'total_overdue_amount': total_overdue_amount,
        
        # Timeline
        'timeline_activities': timeline_activities,
    }
    
    return render(request, 'users/client_complete_history.html', context)


@login_required
def client_create(request):
    """Create a new client with comprehensive registration form"""
    # Check if user has permission to create clients
    if not request.user.has_permission('clients', 'create'):
        messages.error(request, 'You do not have permission to create clients.')
        return redirect('users:client_list')
    
    if request.method == 'POST':
        try:
            # Extract form data
            full_name = request.POST.get('first_name', '').strip()
            # Split full name into first and last name
            name_parts = full_name.split(' ', 1)
            first_name = name_parts[0] if name_parts else ''
            last_name = name_parts[1] if len(name_parts) > 1 else ''
            
            # Get branch assignment
            branch_id = request.POST.get('branch')
            branch = None
            if branch_id:
                try:
                    branch = Branch.objects.get(id=branch_id)
                except Branch.DoesNotExist:
                    messages.error(request, 'Invalid branch selected.')
                    return redirect('users:client_create')
            
            personal_data = {
                'first_name': first_name,
                'last_name': last_name,
                'email': request.POST.get('email'),
                'phone_number': request.POST.get('phone_number'),
                'date_of_birth': request.POST.get('date_of_birth') or None,
                'gender': request.POST.get('gender'),
                'id_number': request.POST.get('id_number'),
                'nationality': request.POST.get('nationality', 'Kenyan'),
                'marital_status': request.POST.get('marital_status'),
                'address': request.POST.get('address') or request.POST.get('physical_address'),
                'physical_address': request.POST.get('physical_address') or request.POST.get('address'),
                'city': request.POST.get('city'),
                'county': request.POST.get('county'),
                'postal_code': request.POST.get('postal_code'),
                'employer': request.POST.get('employer'),
                'kra_pin': request.POST.get('kra_pin'),
            }
            
            # Handle monthly income
            monthly_income = request.POST.get('monthly_income')
            if monthly_income:
                try:
                    personal_data['monthly_income'] = float(monthly_income)
                except (ValueError, TypeError):
                    personal_data['monthly_income'] = None
            
            # Get business type and handle "Other" option
            business_type = request.POST.get('business_type')
            if business_type == 'other':
                business_type = request.POST.get('other_business_type')

            business_data = {
                'business_name': request.POST.get('business_name'),
                'business_type': business_type,
                'business_address': request.POST.get('business_address'),
                'business_registration_number': request.POST.get('business_registration_number'),
            }
            
            # Emergency contact information
            emergency_data = {
                'emergency_contact_name': request.POST.get('emergency_contact_name'),
                'emergency_contact_phone': request.POST.get('emergency_contact_phone'),
                'emergency_contact_relationship': request.POST.get('emergency_contact_relationship'),
            }
            
            # Next of kin information
            next_of_kin_data = {
                'next_of_kin_name': request.POST.get('next_of_kin_name'),
                'next_of_kin_phone': request.POST.get('next_of_kin_phone'),
                'next_of_kin_relationship': request.POST.get('next_of_kin_relationship'),
                'next_of_kin_id_number': request.POST.get('next_of_kin_id_number'),
            }
            
            # Bank details
            bank_data = {
                'bank_name': request.POST.get('bank_name'),
                'bank_branch': request.POST.get('bank_branch'),
                'account_number': request.POST.get('account_number'),
                'account_name': request.POST.get('account_name'),
                'mpesa_number': request.POST.get('mpesa_number') or request.POST.get('phone_number'),
            }
            
            # Recommender information
            recommender_data = {
                'recommender_name': request.POST.get('recommender_name'),
                'recommender_id': request.POST.get('recommender_id'),
                'recommender_tel': request.POST.get('recommender_tel'),
                'recommender_mobile': request.POST.get('recommender_mobile'),
                'recommender_residence': request.POST.get('recommender_residence'),
            }
            
            # Guarantor information
            guarantor_data = {
                'guarantor_name': request.POST.get('guarantor_name'),
                'guarantor_id': request.POST.get('guarantor_id'),
                'guarantor_tel': request.POST.get('guarantor_tel'),
                'guarantor_mobile': request.POST.get('guarantor_mobile'),
                'guarantor_residence': request.POST.get('guarantor_residence'),
            }
            
            # Additional business and personal information
            additional_data = {
                'place_of_birth': request.POST.get('place_of_birth'),
                'domicile': request.POST.get('domicile'),
                'cp_domicile': request.POST.get('cp_domicile'),
                'physical_location': request.POST.get('physical_location'),
                'postal_code_business': request.POST.get('postal_code_business'),
                'declaration_name': request.POST.get('declaration_name'),
                'personal_pin': request.POST.get('personal_pin'),
                'source_of_funds': request.POST.get('source_of_funds'),
            }
            
            # Handle capital invested
            capital_invested = request.POST.get('capital_invested')
            if capital_invested:
                try:
                    additional_data['capital_invested'] = float(capital_invested)
                except (ValueError, TypeError):
                    additional_data['capital_invested'] = None
            
            # Handle expected turnover
            expected_turnover = request.POST.get('expected_turnover')
            if expected_turnover:
                try:
                    additional_data['expected_turnover'] = float(expected_turnover)
                except (ValueError, TypeError):
                    additional_data['expected_turnover'] = None
            
            # Handle start time
            start_time = request.POST.get('start_time')
            if start_time:
                additional_data['start_time'] = start_time
            
            # Handle registration date
            registration_date = request.POST.get('registration_date')
            if registration_date:
                additional_data['registration_date'] = registration_date
            
            # Handle registration fee
            registration_fee_data = {}
            registration_fee_amount = request.POST.get('registration_fee_amount')
            if registration_fee_amount:
                try:
                    registration_fee_data['registration_fee_amount'] = float(registration_fee_amount)
                except (ValueError, TypeError):
                    pass
            
            registration_fee_paid = request.POST.get('registration_fee_paid')
            if registration_fee_paid == 'true':
                registration_fee_data['registration_fee_paid'] = True
                registration_fee_data['registration_fee_payment_method'] = request.POST.get('registration_fee_payment_method')
                registration_fee_data['registration_fee_receipt_number'] = request.POST.get('registration_fee_receipt_number')
                registration_fee_data['registration_fee_payment_date'] = request.POST.get('registration_fee_payment_date')
                registration_fee_data['registration_fee_notes'] = request.POST.get('registration_fee_notes')
            else:
                registration_fee_data['registration_fee_paid'] = False
            
            # Validate required fields
            required_fields = ['phone_number', 'date_of_birth', 'gender', 'id_number', 'nationality', 'physical_address', 'city', 'business_name', 'business_type']
            missing_fields = []
            for field in required_fields:
                if not request.POST.get(field):
                    missing_fields.append(field.replace("_", " ").title())
            
            # Validate required file fields
            required_file_fields = ['id_document', 'selfie']
            missing_file_fields = []
            for field in required_file_fields:
                if not request.FILES.get(field):
                    missing_file_fields.append(field.replace('_', ' ').title())
            if missing_fields or missing_file_fields:
                all_missing = missing_fields + missing_file_fields
                messages.error(request, f'Required fields missing: {", ".join(all_missing)}')
                return render(request, 'users/client_create.html', {
                    'business_types': [
                        ('retail', 'Retail'),
                        ('agriculture', 'Agriculture'),
                        ('transport', 'Transport'),
                        ('manufacturing', 'Manufacturing'),
                        ('services', 'Services'),
                        ('technology', 'Technology'),
                    ],
                    'genders': CustomUser._meta.get_field('gender').choices,
                    'form_data': request.POST
                })
            
            # Check if user already exists
            if personal_data['email'] and CustomUser.objects.filter(email=personal_data['email']).exists():
                messages.error(request, 'This email address is already registered. Please use a different email address.')
                return render(request, 'users/client_create.html', {
                    'business_types': [
                        ('retail', 'Retail'),
                        ('agriculture', 'Agriculture'),
                        ('transport', 'Transport'),
                        ('manufacturing', 'Manufacturing'),
                        ('services', 'Services'),
                        ('technology', 'Technology'),
                    ],
                    'genders': CustomUser._meta.get_field('gender').choices,
                    'form_data': request.POST
                })
            
            if CustomUser.objects.filter(phone_number=personal_data['phone_number']).exists():
                messages.error(request, 'This phone number is already registered. Please use a different phone number.')
                return render(request, 'users/client_create.html', {
                    'business_types': [
                        ('retail', 'Retail'),
                        ('agriculture', 'Agriculture'),
                        ('transport', 'Transport'),
                        ('manufacturing', 'Manufacturing'),
                        ('services', 'Services'),
                        ('technology', 'Technology'),
                    ],
                    'genders': CustomUser._meta.get_field('gender').choices,
                    'form_data': request.POST
                })
            
            # Create user
            # Remove email and phone_number from personal_data to avoid duplicates
            user_data = personal_data.copy()
            email = user_data.pop('email')
            phone_number = user_data.pop('phone_number')
            
            # Filter out fields that don't exist on CustomUser model
            # Get all valid field names from the model
            valid_fields = {f.name for f in CustomUser._meta.get_fields()}
            
            def filter_valid_fields(data_dict):
                """Filter dictionary to only include fields that exist on CustomUser model"""
                return {k: v for k, v in data_dict.items() if k in valid_fields and v is not None and v != ''}
            
            # Map 'address' to 'physical_address' if it exists
            if 'address' in user_data:
                user_data['physical_address'] = user_data.pop('address')
            
            # Filter each data dictionary to only include valid fields
            filtered_user_data = filter_valid_fields(user_data)
            filtered_business_data = filter_valid_fields(business_data)
            filtered_additional_data = filter_valid_fields(additional_data)
            filtered_recommender_data = filter_valid_fields(recommender_data)
            filtered_guarantor_data = filter_valid_fields(guarantor_data)
            filtered_registration_fee_data = filter_valid_fields(registration_fee_data)
            
            # Note: emergency_data, next_of_kin_data, and bank_data fields don't exist on the model
            # so we filter them out (they may be stored elsewhere or in a future migration)
            
            user = CustomUser.objects.create_user(
                username=phone_number,
                email=email,
                phone_number=phone_number,
                **filtered_user_data,
                **filtered_business_data,
                **filtered_additional_data,
                **filtered_recommender_data,
                **filtered_guarantor_data,
                **filtered_registration_fee_data,
                role='borrower',
                status='pending_approval',  # Client requires admin approval
                branch=branch  # Add branch assignment
            )
            
            # Handle file uploads
            if request.FILES.get('id_document'):
                user.id_document = request.FILES['id_document']
            if request.FILES.get('selfie'):
                user.selfie = request.FILES['selfie']
            if request.FILES.get('utility_bill'):
                user.utility_bill = request.FILES['utility_bill']
            if request.FILES.get('bank_statement'):
                user.bank_statement = request.FILES['bank_statement']
            if request.FILES.get('logbook'):
                user.logbook = request.FILES['logbook']
            if request.FILES.get('title_deed'):
                user.title_deed = request.FILES['title_deed']
            if request.FILES.get('signature'):
                user.signature = request.FILES['signature']
            
            user.save()
            
            # Create audit log
            AuditLog.objects.create(
                user=request.user,
                action='create',
                model_name='CustomUser',
                object_id=str(user.id),
                description=f'Created new client awaiting approval: {user.get_full_name()}'
            )
            
            messages.success(request, f'Client {user.get_full_name()} registered successfully! Awaiting admin approval.')
            return redirect('users:client_list')
            
        except Exception as e:
            # Make error messages more user-friendly
            error_msg = str(e)
            if "Duplicate entry" in error_msg and "id_number" in error_msg:
                error_msg = "This ID number is already registered. Please check and try again."
            elif "Duplicate entry" in error_msg and "phone_number" in error_msg:
                error_msg = "This phone number is already registered. Please use a different phone number."
            elif "Duplicate entry" in error_msg and "email" in error_msg:
                error_msg = "This email address is already registered. Please use a different email address."
            messages.error(request, f'Unable to create client: {error_msg}')
    
    # Get system settings for file upload
    from utils.models import SystemSetting
    max_file_size_mb = SystemSetting.get_int('max_file_size_mb', 10)
    
    # Get all active branches
    branches = Branch.objects.filter(is_active=True).order_by('name')
    
    context = {
        'business_types': [
            ('retail', 'Retail'),
            ('agriculture', 'Agriculture'),
            ('transport', 'Transport'),
            ('manufacturing', 'Manufacturing'),
            ('services', 'Services'),
            ('technology', 'Technology'),
        ],
        'genders': CustomUser._meta.get_field('gender').choices,
        'max_file_size_mb': max_file_size_mb,
        'branches': branches,  # Add branches to context
    }
    
    return render(request, 'users/client_create.html', context)


@login_required
def client_update(request, client_id):
    """Update client information"""
    # Check if user has permission to edit clients
    if not request.user.has_permission('clients', 'edit'):
        messages.error(request, 'You do not have permission to edit clients.')
        return redirect('users:client_list')
    
    client = get_object_or_404(CustomUser, pk=client_id, role='borrower')
    
    if request.method == 'POST':
        try:
            # Handle branch assignment
            branch_id = request.POST.get('branch')
            if branch_id:
                try:
                    branch = Branch.objects.get(id=branch_id)
                    client.branch = branch
                except Branch.DoesNotExist:
                    messages.error(request, 'Invalid branch selected.')
                    return redirect('users:client_update', client_id=client_id)
            
            # Update fields
            for field in ['first_name', 'last_name', 'email', 'phone_number', 'date_of_birth', 
                         'gender', 'id_number', 'marital_status', 'address', 'physical_address',
                         'city', 'county', 'postal_code', 'business_name', 'business_type', 
                         'employer', 'nationality', 'kra_pin', 'business_address', 
                         'business_registration_number', 'emergency_contact_name', 
                         'emergency_contact_phone', 'emergency_contact_relationship',
                         'next_of_kin_name', 'next_of_kin_phone', 'next_of_kin_relationship',
                         'next_of_kin_id_number', 'bank_name', 'bank_branch', 'account_number',
                         'account_name', 'mpesa_number', 'recommender_name', 'recommender_id',
                         'recommender_tel', 'recommender_mobile', 'recommender_residence',
                         'guarantor_name', 'guarantor_id', 'guarantor_tel', 'guarantor_mobile',
                         'guarantor_residence', 'place_of_birth', 'domicile', 'cp_domicile',
                         'physical_location', 'postal_code_business', 'declaration_name',
                         'personal_pin', 'source_of_funds', 'nickname', 'country',
                         'registration_fee_payment_method', 'registration_fee_receipt_number',
                         'registration_fee_notes']:
                if field in request.POST:
                    value = request.POST[field]
                    # Don't set empty strings for optional fields
                    if value or field in ['first_name', 'last_name', 'phone_number']:
                        setattr(client, field, value)
            
            # Handle monthly_income separately
            monthly_income = request.POST.get('monthly_income')
            if monthly_income:
                try:
                    client.monthly_income = float(monthly_income)
                except ValueError:
                    client.monthly_income = None
            else:
                client.monthly_income = None
            
            # Handle capital_invested
            capital_invested = request.POST.get('capital_invested')
            if capital_invested:
                try:
                    client.capital_invested = float(capital_invested)
                except ValueError:
                    client.capital_invested = None
            
            # Handle expected_turnover
            expected_turnover = request.POST.get('expected_turnover')
            if expected_turnover:
                try:
                    client.expected_turnover = float(expected_turnover)
                except ValueError:
                    client.expected_turnover = None
            
            # Handle registration_fee_amount
            registration_fee_amount = request.POST.get('registration_fee_amount')
            if registration_fee_amount:
                try:
                    client.registration_fee_amount = float(registration_fee_amount)
                except ValueError:
                    pass
            
            # Handle registration_fee_paid
            registration_fee_paid = request.POST.get('registration_fee_paid')
            if registration_fee_paid:
                client.registration_fee_paid = registration_fee_paid == 'true' or registration_fee_paid == '1'
            
            # Handle registration_fee_payment_date
            registration_fee_payment_date = request.POST.get('registration_fee_payment_date')
            if registration_fee_payment_date:
                client.registration_fee_payment_date = registration_fee_payment_date
            
            # Handle start_time
            start_time = request.POST.get('start_time')
            if start_time:
                client.start_time = start_time
            
            # Handle registration_date
            registration_date = request.POST.get('registration_date')
            if registration_date:
                client.registration_date = registration_date
            
            # Handle nationality field specifically
            if 'nationality' in request.POST:
                client.nationality = request.POST['nationality']
            
            # Only update file fields if a new file is uploaded:
            for field in ['id_document', 'selfie', 'utility_bill', 'bank_statement', 'logbook', 'title_deed', 'signature']:
                if request.FILES.get(field):
                    setattr(client, field, request.FILES[field])
            
            client.save()
            
            # Invalidate cache for this client's popup data
            invalidate_client_popup_cache(client_id)
            
            # Create audit log
            AuditLog.objects.create(
                user=request.user,
                action='update',
                model_name='CustomUser',
                object_id=str(client.id),
                description=f'Updated client: {client.get_full_name()}'
            )
            
            messages.success(request, 'Client information updated successfully!', extra_tags='client_update')
            return redirect('users:client_list')
            
        except Exception as e:
            messages.error(request, f'Error updating client: {str(e)}', extra_tags='client_update')
    
    # Get system settings for file upload
    from utils.models import SystemSetting
    max_file_size_mb = SystemSetting.get_int('max_file_size_mb', 10)
    
    # Get all active branches
    branches = Branch.objects.filter(is_active=True).order_by('name')
    
    context = {
        'client': client,
        'business_types': [
            ('retail', 'Retail'),
            ('agriculture', 'Agriculture'),
            ('transport', 'Transport'),
            ('manufacturing', 'Manufacturing'),
            ('services', 'Services'),
            ('technology', 'Technology'),
        ],
        'genders': CustomUser._meta.get_field('gender').choices,
        'max_file_size_mb': max_file_size_mb,
        'branches': branches,  # Add branches to context
    }
    
    return render(request, 'users/client_update.html', context)


@login_required
def client_delete(request, client_id):
    """Enhanced client deletion with comprehensive dependency handling"""
    # Check if user has permission to delete clients
    if not request.user.has_permission('clients', 'delete'):
        messages.error(request, 'You do not have permission to delete clients.')
        return redirect('users:client_list')
    
    client = get_object_or_404(CustomUser, pk=client_id, role='borrower')
    
    # Get client dependencies for display
    dependencies = get_client_dependencies(client)
    
    if request.method == 'POST':
        action = request.POST.get('action')
        
        try:
            with transaction.atomic():
                if action == 'blacklist':
                    # Blacklist the client (soft delete)
                    client.status = 'blacklisted'
                    client.is_active = False
                    client.save()
                    
                    # Invalidate cache for this client's popup data
                    invalidate_client_popup_cache(client_id)
                    
                    # Create audit log
                    AuditLog.objects.create(
                        user=request.user,
                        action='blacklist',
                        model_name='CustomUser',
                        object_id=str(client.id),
                        description=f'Blacklisted client: {client.get_full_name()}'
                    )
                    
                    messages.success(request, f'Client {client.get_full_name()} has been blacklisted successfully.', extra_tags='client_list')
                    
                elif action == 'delete':
                    # Use safe deletion system
                    success, message = safe_delete_client_permanently(client, request.user)
                    
                    if success:
                        messages.success(request, message, extra_tags='client_list')
                    else:
                        messages.error(request, f'Deletion failed: {message}', extra_tags='client_list')
                        return render(request, 'users/client_confirm_delete.html', {
                            'client': client,
                            'dependencies': dependencies,
                            'error': message
                        })
        
        except Exception as e:
            messages.error(request, f'An error occurred: {str(e)}', extra_tags='client_list')
            return render(request, 'users/client_confirm_delete.html', {
                'client': client,
                'dependencies': dependencies,
                'error': str(e)
            })
        
        return redirect('users:client_list')
    
    return render(request, 'users/client_confirm_delete.html', {
        'client': client,
        'dependencies': dependencies
    })


@login_required
def client_bulk_delete(request):
    """Bulk delete multiple clients"""
    if request.method == 'POST':
        client_ids = request.POST.getlist('client_ids')
        action = request.POST.get('action')
        
        if not client_ids:
            messages.error(request, 'No clients selected for deletion.')
            return redirect('users:client_list')
        
        # Get selected clients
        clients = CustomUser.objects.filter(id__in=client_ids, role='borrower')
        
        if not clients.exists():
            messages.error(request, 'No valid clients found.')
            return redirect('users:client_list')
        
        # Get dependencies for all clients
        total_dependencies = 0
        client_data = []
        for client in clients:
            deps = get_client_dependencies(client)
            total_dependencies += deps.get('total', 0)
            client_data.append({
                'client': client,
                'dependencies': deps
            })
        
        if request.POST.get('confirm') == 'yes':
            # Process the bulk deletion
            success_count = 0
            error_count = 0
            errors = []
            
            try:
                with transaction.atomic():
                    for data in client_data:
                        client = data['client']
                        try:
                            if action == 'blacklist':
                                client.status = 'blacklisted'
                                client.is_active = False
                                client.save()
                                
                                AuditLog.objects.create(
                                    user=request.user,
                                    action='blacklist',
                                    model_name='CustomUser',
                                    object_id=str(client.id),
                                    description=f'Bulk blacklisted client: {client.get_full_name()}'
                                )
                                success_count += 1
                                
                            elif action == 'delete':
                                success, message = safe_delete_client_permanently(client, request.user)
                                if success:
                                    success_count += 1
                                else:
                                    errors.append(f"{client.get_full_name()}: {message}")
                                    error_count += 1
                                    
                        except Exception as e:
                            errors.append(f"{client.get_full_name()}: {str(e)}")
                            error_count += 1
                
                # Show results
                if success_count > 0:
                    action_word = 'blacklisted' if action == 'blacklist' else 'deleted'
                    messages.success(request, f'Successfully {action_word} {success_count} client(s).')
                
                if error_count > 0:
                    error_msg = f'Failed to process {error_count} client(s): ' + '; '.join(errors[:3])
                    if len(errors) > 3:
                        error_msg += f' and {len(errors) - 3} more...'
                    messages.error(request, error_msg)
                    
            except Exception as e:
                messages.error(request, f'Bulk operation failed: {str(e)}')
            
            return redirect('users:client_list')
        
        # Show confirmation page
        return render(request, 'users/client_bulk_delete_confirm.html', {
            'client_data': client_data,
            'total_clients': len(client_data),
            'total_dependencies': total_dependencies,
            'action': action,
            'client_ids': client_ids
        })
    
    return redirect('users:client_list')


@login_required
def client_delete_api(request, client_id):
    """AJAX API endpoint for client deletion"""
    if request.method != 'POST':
        return JsonResponse({'success': False, 'error': 'Method not allowed'}, status=405)
    
    try:
        client = get_object_or_404(CustomUser, pk=client_id, role='borrower')
        action = request.POST.get('action', 'blacklist')
        
        # Get dependencies for response
        dependencies = get_client_dependencies(client)
        
        if action == 'blacklist':
            with transaction.atomic():
                client.status = 'blacklisted'
                client.is_active = False
                client.save()
                
                invalidate_client_popup_cache(client_id)
                
                AuditLog.objects.create(
                    user=request.user,
                    action='blacklist',
                    model_name='CustomUser',
                    object_id=str(client.id),
                    description=f'Blacklisted client via API: {client.get_full_name()}'
                )
                
                return JsonResponse({
                    'success': True,
                    'message': f'Client {client.get_full_name()} has been blacklisted successfully.',
                    'action': 'blacklist',
                    'dependencies_processed': dependencies.get('total', 0)
                })
        
        elif action == 'delete':
            success, message = safe_delete_client_permanently(client, request.user)
            
            return JsonResponse({
                'success': success,
                'message': message,
                'action': 'delete',
                'dependencies_processed': dependencies.get('total', 0) if success else 0
            })
        
        else:
            return JsonResponse({'success': False, 'error': 'Invalid action'}, status=400)
            
    except Exception as e:
        return JsonResponse({'success': False, 'error': str(e)}, status=500)


@login_required
def client_export(request):
    """Export clients data to CSV/Excel"""
    # Check if user has permission to export clients
    if not request.user.has_permission('clients', 'export'):
        messages.error(request, 'You do not have permission to export client data.')
        return redirect('users:client_list')
    # Implementation for data export
    pass


@login_required
def profile(request):
    """User profile view"""
    return render(request, 'users/profile.html')


@login_required
def edit_profile(request):
    """Edit user profile"""
    if request.method == 'POST':
        user = request.user
        
        # Update basic information
        user.first_name = request.POST.get('first_name', user.first_name)
        user.last_name = request.POST.get('last_name', user.last_name)
        user.email = request.POST.get('email', user.email)
        user.phone_number = request.POST.get('phone_number', user.phone_number)
        
        # Handle profile image upload
        if 'profile_image' in request.FILES:
            profile_image = request.FILES['profile_image']
            
            # Validate file type
            allowed_types = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif']
            try:
                # Use magic if available, otherwise rely on file extension
                if MAGIC_AVAILABLE:
                    file_type = magic.from_buffer(profile_image.read(), mime=True)
                    profile_image.seek(0)  # Reset file pointer
                else:
                    # Fallback to checking file extension
                    file_name = profile_image.name.lower()
                    if file_name.endswith(('.jpg', '.jpeg')):
                        file_type = 'image/jpeg'
                    elif file_name.endswith('.png'):
                        file_type = 'image/png'
                    elif file_name.endswith('.gif'):
                        file_type = 'image/gif'
                    else:
                        file_type = 'unknown'
                
                if file_type in allowed_types:
                    # Resize image if needed
                    try:
                        img = Image.open(profile_image)
                        if img.mode in ("RGBA", "P"):
                            img = img.convert("RGB")
                        
                        # Resize to max 300x300 while maintaining aspect ratio
                        img.thumbnail((300, 300), Image.Resampling.LANCZOS)
                        
                        # Save to BytesIO
                        output = BytesIO()
                        img.save(output, format='JPEG', quality=85)
                        output.seek(0)
                        
                        # Delete old profile image if exists
                        if user.profile_image:
                            user.profile_image.delete(save=False)
                        
                        # Create new file
                        user.profile_image.save(
                            f'profile_{user.id}.jpg',
                            ContentFile(output.read()),
                            save=False
                        )
                        messages.success(request, 'Profile image updated successfully!')
                    except Exception as e:
                        messages.warning(request, f'Profile image uploaded but could not be processed: {str(e)}')
                        user.profile_image = profile_image
                else:
                    messages.error(request, 'Invalid image format. Please upload JPEG, PNG, or GIF files only.')
            except Exception as e:
                messages.error(request, f'Error processing image: {str(e)}')
        
        # Handle profile image removal
        if request.POST.get('remove_profile_image') == 'true':
            if user.profile_image:
                user.profile_image.delete(save=False)
                user.profile_image = None
                messages.success(request, 'Profile image removed successfully!')
        
        try:
            user.save()
            messages.success(request, 'Profile updated successfully!')
        except Exception as e:
            messages.error(request, f'Error updating profile: {str(e)}')
        
        return redirect('users:profile')
    
    return render(request, 'users/edit_profile.html', {'user': request.user})


@login_required
def kyc_documents(request):
    """KYC documents management"""
    return render(request, 'users/kyc_documents.html')


@login_required
def upload_kyc(request):
    """Upload KYC documents"""
    # Check if user has permission to upload customer documents
    if not request.user.has_permission('customer_documents', 'upload'):
        messages.error(request, 'You do not have permission to upload KYC documents.')
        return redirect('users:kyc_documents')
    
    return render(request, 'users/upload_kyc.html')


# Admin Management Views
@login_required
def admin_list(request):
    """List all staff users - accessible by admins and superusers"""
    
    # Check if user has admin access
    if not (request.user.is_superuser or request.user.role == 'admin'):
        messages.error(request, 'You do not have permission to access admin management.')
        return redirect('dashboard')
    
    try:
        # Get filter parameters
        search = request.GET.get('search', '')
        status_filter = request.GET.get('status', 'all')
        
        # Base queryset - get all staff users (admin, team_leader, loan_officer, secretary)
        admins = CustomUser.objects.filter(is_staff=True).select_related('branch')
        
        # Apply filters
        if search:
            admins = admins.filter(
                Q(first_name__icontains=search) |
                Q(last_name__icontains=search) |
                Q(email__icontains=search) |
                Q(phone_number__icontains=search) |
                Q(username__icontains=search)
            )
        
        role_filter = request.GET.get('role', 'all')
        if role_filter != 'all':
            admins = admins.filter(role=role_filter)
        
        if status_filter != 'all':
            admins = admins.filter(status=status_filter)
        
        # Pagination
        paginator = Paginator(admins, 10)
        page_number = request.GET.get('page')
        page_obj = paginator.get_page(page_number)
        
        # Get statistics for all staff users
        all_staff = CustomUser.objects.filter(is_staff=True)
        
        context = {
            'admins': page_obj,
            'search': search,
            'status_filter': status_filter,
            'role_filter': role_filter,
            'total_staff': all_staff.count(),
            'admin_count': all_staff.filter(role='admin').count(),
            'team_leader_count': all_staff.filter(role='team_leader').count(),
            'loan_officer_count': all_staff.filter(role='loan_officer').count(),
            'secretary_count': all_staff.filter(role='secretary').count(),
        }
        
        return render(request, 'users/admin_list.html', context)
        
    except Exception as e:
        print(f"Error in admin_list view: {str(e)}")
        return render(request, 'users/admin_list.html', {
            'admins': [],
            'search': '',
            'status_filter': 'all',
            'role_filter': 'all',
            'total_staff': 0,
            'admin_count': 0,
            'team_leader_count': 0,
            'loan_officer_count': 0,
            'secretary_count': 0,
            'error_message': str(e)
        })


@login_required
def admin_create(request):
    """Create a new staff user with role-based permissions"""
    
    # Check if user has admin access
    if not (request.user.is_superuser or request.user.role == 'admin'):
        messages.error(request, 'You do not have permission to create staff users.')
        return redirect('dashboard')
    
    if request.method == 'POST':
        # Get form data
        username = request.POST.get('username')
        email = request.POST.get('email')
        phone_number = request.POST.get('phone_number')
        first_name = request.POST.get('first_name')
        last_name = request.POST.get('last_name')
        role = request.POST.get('role')
        password = request.POST.get('password')
        confirm_password = request.POST.get('confirm_password')
        status = request.POST.get('status', 'active')
        
        # Get branch assignment
        branch_id = request.POST.get('branch')
        branch = None
        if branch_id:
            try:
                branch = Branch.objects.get(id=branch_id)
            except Branch.DoesNotExist:
                messages.error(request, 'Invalid branch selected.')
                return redirect('users:admin_create')
        
        # Get custom permissions
        custom_permissions = {}
        from users.models import DefaultRolePermission
        for module_choice in DefaultRolePermission.MODULE_CHOICES:
            module = module_choice[0]
            custom_permissions[module] = {}
            for action_choice in DefaultRolePermission.ACTION_CHOICES:
                action = action_choice[0]
                custom_permissions[module][action] = request.POST.get(f'perm_{module}_{action}') == 'on'
        
        # Validate required fields
        if not all([username, email, phone_number, first_name, last_name, role, password]):
            messages.error(request, 'All fields are required.')
            return redirect('users:admin_create')
        
        # Validate password
        if password != confirm_password:
            messages.error(request, 'Passwords do not match.')
            return redirect('users:admin_create')
        
        # Check if username or email already exists
        if CustomUser.objects.filter(username=username).exists():
            messages.error(request, 'Username already exists.')
            return redirect('users:admin_create')
        
        if CustomUser.objects.filter(email=email).exists():
            messages.error(request, 'Email already exists.')
            return redirect('users:admin_create')
        
        if CustomUser.objects.filter(phone_number=phone_number).exists():
            messages.error(request, 'Phone number already exists.')
            return redirect('users:admin_create')
        
        try:
            # Create user
            user = CustomUser.objects.create_user(
                username=username,
                email=email,
                phone_number=phone_number,
                first_name=first_name,
                last_name=last_name,
                role=role,
                password=password,
                status=status,
                is_staff=True,
                is_superuser=(role == 'admin'),
                is_verified=True,  # Mark as verified since it's created by admin
                branch=branch  # Add branch assignment
            )
            
            # Handle profile image upload
            if 'profile_image' in request.FILES:
                profile_image = request.FILES['profile_image']
                
                # Validate file type
                allowed_types = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif']
                # Use magic if available, otherwise rely on file extension
                if MAGIC_AVAILABLE:
                    file_type = magic.from_buffer(profile_image.read(), mime=True)
                    profile_image.seek(0)  # Reset file pointer
                else:
                    # Fallback to checking file extension
                    file_name = profile_image.name.lower()
                    if file_name.endswith(('.jpg', '.jpeg')):
                        file_type = 'image/jpeg'
                    elif file_name.endswith('.png'):
                        file_type = 'image/png'
                    elif file_name.endswith('.gif'):
                        file_type = 'image/gif'
                    else:
                        file_type = 'unknown'
                
                if file_type in allowed_types:
                    # Resize image if needed
                    try:
                        img = Image.open(profile_image)
                        if img.mode in ("RGBA", "P"):
                            img = img.convert("RGB")
                        
                        # Resize to max 300x300 while maintaining aspect ratio
                        img.thumbnail((300, 300), Image.Resampling.LANCZOS)
                        
                        # Save to BytesIO
                        output = BytesIO()
                        img.save(output, format='JPEG', quality=85)
                        output.seek(0)
                        
                        # Create new file
                        user.profile_image.save(
                            f'profile_{user.id}.jpg',
                            ContentFile(output.read()),
                            save=True
                        )
                    except Exception as e:
                        messages.warning(request, f'Profile image uploaded but could not be processed: {str(e)}')
                        user.profile_image = profile_image
                        user.save()
                else:
                    messages.warning(request, 'Invalid image format. Please upload JPEG, PNG, or GIF files only.')
            
            
            # Create custom permissions if they differ from defaults
            from users.models import RolePermission, DefaultRolePermission, UserPermission
            try:
                for module, actions in custom_permissions.items():
                    for action, is_allowed in actions.items():
                        # Check if this differs from default permissions
                        try:
                            default_perm = DefaultRolePermission.objects.get(role=role, module=module, action=action)
                            if default_perm.is_allowed != is_allowed:
                                # Create custom user permission
                                UserPermission.objects.create(
                                    user=user,
                                    module=module,
                                    action=action,
                                    is_allowed=is_allowed,
                                    granted_by=request.user,
                                    reason=f'Custom permission set during user creation'
                                )
                        except DefaultRolePermission.DoesNotExist:
                            # Create custom user permission for non-default actions
                            UserPermission.objects.create(
                                user=user,
                                module=module,
                                action=action,
                                is_allowed=is_allowed,
                                granted_by=request.user,
                                reason=f'Custom permission set during user creation'
                            )
            except Exception as perm_error:
                # Don't fail user creation for permission errors
                messages.warning(request, f'User created but permission setup had issues: {str(perm_error)}')
            
            # Log the creation
            try:
                request.user.log_access(
                    action='create',
                    module='users',
                    object_type='CustomUser',
                    object_id=str(user.id),
                    description=f'Created new {role} user: {user.get_full_name()} with custom permissions',
                    request=request
                )
            except Exception as log_error:
                # Don't fail user creation for logging errors
                pass
            
            messages.success(request, f'Successfully created {role} user: {user.get_full_name()}')
            return redirect('users:admin_list')
            
        except Exception as e:
            messages.error(request, f'Error creating user: {str(e)}')
            return redirect('users:admin_create')
    
    # Get available roles for staff members
    staff_roles = [role for role in CustomUser.ROLE_CHOICES if role[0] in ['admin', 'team_leader', 'loan_officer', 'secretary']]
    
    # Get all active branches
    branches = Branch.objects.filter(is_active=True).order_by('name')
    
    # Get default permissions for each role
    from users.models import DefaultRolePermission
    default_permissions = {}
    for role, _ in staff_roles:
        default_permissions[role] = {}
        for module_choice in DefaultRolePermission.MODULE_CHOICES:
            module = module_choice[0]
            default_permissions[role][module] = {}
            for action_choice in DefaultRolePermission.ACTION_CHOICES:
                action = action_choice[0]
                try:
                    perm = DefaultRolePermission.objects.get(role=role, module=module, action=action)
                    default_permissions[role][module][action] = perm.is_allowed
                except DefaultRolePermission.DoesNotExist:
                    default_permissions[role][module][action] = False
    
    context = {
        'staff_roles': staff_roles,
        'default_permissions': default_permissions,
        'status_choices': CustomUser.STATUS_CHOICES,
        'branches': branches,  # Add branches to context
    }
    
    return render(request, 'users/admin_create.html', context)


@login_required
def admin_detail(request, admin_id):
    """Detailed view of a staff user"""
    
    # Check if user has admin access
    if not (request.user.is_superuser or request.user.role == 'admin'):
        messages.error(request, 'You do not have permission to view staff details.')
        return redirect('dashboard')
    
    admin = get_object_or_404(CustomUser, id=admin_id, is_staff=True)
    
    # Get access logs for this admin
    try:
        from .models import UserAccessLog
        audit_logs = UserAccessLog.objects.filter(user=admin).order_by('-accessed_at')[:10]
    except ImportError:
        audit_logs = []
    
    context = {
        'admin': admin,
        'audit_logs': audit_logs,
    }
    
    return render(request, 'users/admin_detail.html', context)


@login_required
def admin_update(request, admin_id):
    """Update staff user information"""
    
    # Check if user has admin access
    if not (request.user.is_superuser or request.user.role == 'admin'):
        messages.error(request, 'You do not have permission to update staff users.')
        return redirect('dashboard')
    
    admin = get_object_or_404(CustomUser, id=admin_id, is_staff=True)
    
    if request.method == 'POST':
        try:
            # Handle branch assignment
            branch_id = request.POST.get('branch')
            if branch_id:
                try:
                    branch = Branch.objects.get(id=branch_id)
                    admin.branch = branch
                except Branch.DoesNotExist:
                    messages.error(request, 'Invalid branch selected.')
                    return redirect('users:admin_update', admin_id=admin_id)
            else:
                admin.branch = None
            
            # Update basic fields
            admin.first_name = request.POST.get('first_name')
            admin.last_name = request.POST.get('last_name')
            admin.email = request.POST.get('email')
            admin.phone_number = request.POST.get('phone_number')
            admin.status = request.POST.get('status')
            # Handle role and permissions
            role = request.POST.get('role')
            if role:
                admin.role = role
                # Set is_staff and is_superuser based on role
                if role == 'admin':
                    admin.is_staff = True
                    admin.is_superuser = False
                elif role in ['team_leader', 'loan_officer', 'secretary', 'auditor']:
                    admin.is_staff = True
                    admin.is_superuser = False
                else:
                    admin.is_staff = False
                    admin.is_superuser = False
            
            # Update password if provided
            new_password = request.POST.get('new_password')
            confirm_password = request.POST.get('confirm_password')
            if new_password:
                if new_password != confirm_password:
                    messages.error(request, 'Passwords do not match.', extra_tags='admin_update')
                    return redirect('users:admin_update', admin_id=admin_id)
                admin.set_password(new_password)
            
            admin.save()
            
            # Create access log
            request.user.log_access(
                action='update',
                module='users',
                object_type='CustomUser',
                object_id=str(admin.id),
                description=f'Updated staff user: {admin.get_full_name()}',
                request=request
            )
            
            messages.success(request, 'Admin information updated successfully!', extra_tags='admin_list')
            return redirect('users:admin_list')
            
        except Exception as e:
            messages.error(request, f'Error updating admin: {str(e)}', extra_tags='admin_update')
            return redirect('users:admin_update', admin_id=admin_id)
    
    # Get all active branches
    branches = Branch.objects.filter(is_active=True).order_by('name')
    
    context = {
        'admin': admin,
        'status_choices': CustomUser.STATUS_CHOICES,
        'role_choices': CustomUser.ROLE_CHOICES,
        'branches': branches,  # Add branches to context
    }
    
    return render(request, 'users/admin_update.html', context)


@login_required
def admin_delete(request, pk):
    """Delete a staff user (soft delete)"""
    
    # Check if user has admin access
    if not (request.user.is_superuser or request.user.role == 'admin'):
        messages.error(request, 'You do not have permission to manage staff users.')
        return redirect('dashboard')
    
    admin_user = get_object_or_404(CustomUser, pk=pk, is_staff=True)
    
    # Prevent deleting self
    if admin_user == request.user:
        messages.error(request, 'You cannot delete your own account.')
        return redirect('users:admin_list')
    
    if request.method == 'POST':
        admin_user.status = 'suspended'
        admin_user.is_active = False
        admin_user.save()
        
        # Create access log
        request.user.log_access(
            action='delete',
            module='users',
            object_type='CustomUser',
            object_id=str(admin_user.id),
            description=f'Suspended staff user: {admin_user.get_full_name()}',
            request=request
        )
        
        messages.success(request, f'Admin {admin_user.get_full_name()} has been suspended.')
        return redirect('users:admin_list')
    
    return render(request, 'users/admin_confirm_delete.html', {'admin_user': admin_user})


@login_required
def admin_reactivate(request, pk):
    """Reactivate a suspended staff user"""
    
    # Check if user has admin access
    if not (request.user.is_superuser or request.user.role == 'admin'):
        messages.error(request, 'You do not have permission to manage staff users.')
        return redirect('dashboard')
    
    admin_user = get_object_or_404(CustomUser, pk=pk, is_staff=True)
    
    if request.method == 'POST':
        admin_user.status = 'active'
        admin_user.is_active = True
        admin_user.save()
        
        # Create access log
        request.user.log_access(
            action='update',
            module='users',
            object_type='CustomUser',
            object_id=str(admin_user.id),
            description=f'Reactivated staff user: {admin_user.get_full_name()}',
            request=request
        )
        
        messages.success(request, f'Admin {admin_user.get_full_name()} has been reactivated.')
        return redirect('users:admin_list')
    
    return render(request, 'users/admin_confirm_reactivate.html', {'admin_user': admin_user})


@login_required
def client_popup(request, client_id):
    """Get client data for popup modal - OPTIMIZED VERSION WITH CACHING"""
    try:
        # Check cache first for performance
        from django.core.cache import cache
        cache_key = f'client_popup_{client_id}'
        cached_data = cache.get(cache_key)
        
        if cached_data:
            return JsonResponse(cached_data)
        
        # Get client with select_related to optimize queries
        client = get_object_or_404(CustomUser, id=client_id, role='borrower')
        
        # OPTIMIZED: Use lightweight queries instead of comprehensive analytics
        from django.db.models import Sum, Count, Q
        from decimal import Decimal
        
        # Get basic loan statistics with optimized queries
        client_loans = Loan.objects.filter(borrower=client)
        
        # Single query for all loan statistics
        loan_stats = client_loans.aggregate(
            total_loans=Count('id'),
            active_loans=Count('id', filter=Q(status='active')),
            total_principal=Sum('principal_amount'),
            total_interest=Sum('interest_amount')
        )
        
        # Calculate derived values
        total_borrowed = float(loan_stats['total_principal'] or 0)
        # Calculate total repaid from repayments
        total_repaid = float(Repayment.objects.filter(
            loan__borrower=client
        ).aggregate(total=Sum('amount'))['total'] or 0)
        
        # Calculate correct outstanding amount by summing individual loan outstanding amounts
        outstanding_amount = sum(float(loan.outstanding_amount) for loan in client_loans.filter(status__in=['active', 'rolled_over']))
        active_loans = loan_stats['active_loans'] or 0
        
        # Simple credit score calculation (much faster than comprehensive analytics)
        credit_score = 0
        if total_borrowed > 0:
            repayment_rate = (total_repaid / total_borrowed) * 100
            if repayment_rate >= 90:
                credit_score = 85
            elif repayment_rate >= 75:
                credit_score = 70
            elif repayment_rate >= 50:
                credit_score = 55
            else:
                credit_score = 30
        
        # Get recent loans (limit to 5 for performance)
        recent_loans = client_loans.select_related('application__loan_product').order_by('-created_at')[:5]
        loans_data = []
        
        ordinal_names = ['First', 'Second', 'Third', 'Fourth', 'Fifth']
        for index, loan in enumerate(recent_loans):
            loan_name = ordinal_names[index] if index < len(ordinal_names) else f"{index + 1}th"
            
            loans_data.append({
                'loan_number': loan.loan_number,
                'loan_name': f"{loan_name} Loan",
                'product_name': loan.application.loan_product.name if loan.application and loan.application.loan_product else 'N/A',
                'principal_amount': float(loan.principal_amount or 0),
                'interest_amount': float(loan.interest_amount or 0),
                'status': loan.status,
                'status_display': loan.get_status_display() if hasattr(loan, 'get_status_display') else loan.status.title(),
                'disbursement_date': loan.disbursement_date.strftime('%B %d, %Y') if loan.disbursement_date else 'N/A',
                'due_date': loan.due_date.strftime('%B %d, %Y') if loan.due_date else 'N/A',
                'amount_paid': float(loan.amount_paid or 0),
                'outstanding_amount': float(loan.outstanding_amount)  # Use the model property which includes total_amount + penalties - amount_paid
            })
        
        # Simple chart data (much faster than comprehensive analytics)
        status_counts = client_loans.values('status').annotate(count=Count('id'))
        chart_data = {
            'loan_status_distribution': {
                'labels': [item['status'].title() for item in status_counts],
                'data': [item['count'] for item in status_counts],
                'colors': ['#10B981', '#3B82F6', '#EF4444', '#F59E0B', '#8B5CF6']
            },
            'repayment_trend': {
                'labels': ['Last 3 Months', 'Last 6 Months', 'Total'],
                'data': [total_repaid * 0.3, total_repaid * 0.6, total_repaid]  # Simplified trend
            }
        }
        
        # Check documents (keep existing logic as it's fast)
        documents = {
            'id_document': {
                'uploaded': bool(client.id_document),
                'url': client.id_document.url if client.id_document else None,
                'name': 'National ID Document',
                'description': 'Front and back scanned copies'
            },
            'selfie': {
                'uploaded': bool(client.selfie),
                'url': client.selfie.url if client.selfie else None,
                'name': 'Selfie Photo',
                'description': 'Recent photo for verification'
            },
            'utility_bill': {
                'uploaded': bool(client.utility_bill),
                'url': client.utility_bill.url if client.utility_bill else None,
                'name': 'Utility Bill',
                'description': 'Recent utility bill for address verification'
            },
            'bank_statement': {
                'uploaded': bool(client.bank_statement),
                'url': client.bank_statement.url if client.bank_statement else None,
                'name': 'Bank Statement',
                'description': 'Last 6 months bank statements'
            },
            'business_license': {
                'uploaded': bool(client.business_license),
                'url': client.business_license.url if client.business_license else None,
                'name': 'Business License',
                'description': 'Business registration and license documents'
            },
            'tax_certificate': {
                'uploaded': bool(client.tax_certificate),
                'url': client.tax_certificate.url if client.tax_certificate else None,
                'name': 'Tax Certificate',
                'description': 'Tax compliance certificates'
            },
            'logbook': {
                'uploaded': bool(client.logbook),
                'url': client.logbook.url if client.logbook else None,
                'name': 'Logbook',
                'description': 'Vehicle logbook documents'
            },
            'title_deed': {
                'uploaded': bool(client.title_deed),
                'url': client.title_deed.url if client.title_deed else None,
                'name': 'Title Deed',
                'description': 'Property title deed documents'
            },
            'signature': {
                'uploaded': bool(client.signature),
                'url': client.signature.url if client.signature else None,
                'name': 'Digital Signature',
                'description': 'Digital signature image'
            },
            'other_documents': {
                'uploaded': bool(client.other_documents),
                'url': client.other_documents.url if client.other_documents else None,
                'name': 'Other Documents',
                'description': 'Additional supporting documents'
            }
        }
        
        # Prepare client data (keep existing structure for compatibility)
        client_data = {
            # Basic Information
            'id': str(client.id),
            'full_name': client.get_full_name() if hasattr(client, 'get_full_name') else f"{getattr(client, 'first_name', '')} {getattr(client, 'last_name', '')}".strip(),
            'first_name': getattr(client, 'first_name', '') or '',
            'last_name': getattr(client, 'last_name', '') or '',
            'email': getattr(client, 'email', 'N/A') or 'N/A',
            'phone_number': getattr(client, 'phone_number', 'N/A') or 'N/A',
            'id_number': getattr(client, 'id_number', 'N/A') or 'N/A',
            'date_of_birth': client.date_of_birth.strftime('%B %d, %Y') if hasattr(client, 'date_of_birth') and client.date_of_birth else 'N/A',
            'gender': client.get_gender_display() if hasattr(client, 'gender') and client.gender else 'N/A',
            'marital_status': client.get_marital_status_display() if hasattr(client, 'marital_status') and client.marital_status else 'N/A',
            'nationality': getattr(client, 'nationality', 'N/A') or 'N/A',
            'country': getattr(client, 'country', 'N/A') or 'N/A',
            'nickname': getattr(client, 'nickname', 'N/A') or 'N/A',
            'place_of_birth': getattr(client, 'place_of_birth', 'N/A') or 'N/A',
            'domicile': getattr(client, 'domicile', 'N/A') or 'N/A',
            'cp_domicile': getattr(client, 'cp_domicile', 'N/A') or 'N/A',
            'start_time': client.start_time.strftime('%I:%M %p') if hasattr(client, 'start_time') and client.start_time else 'N/A',
            'registration_date': client.registration_date.strftime('%B %d, %Y') if hasattr(client, 'registration_date') and client.registration_date else 'N/A',
            'physical_address': getattr(client, 'physical_address', 'N/A') or 'N/A',
            'city': getattr(client, 'city', 'N/A') or 'N/A',
            'county': getattr(client, 'county', 'N/A') or 'N/A',
            'postal_code': getattr(client, 'postal_code', 'N/A') or 'N/A',
            'postal_code_business': getattr(client, 'postal_code_business', 'N/A') or 'N/A',
            'physical_location': getattr(client, 'physical_location', 'N/A') or 'N/A',
            'status': getattr(client, 'status', 'unknown'),
            'status_display': client.get_status_display() if hasattr(client, 'get_status_display') else getattr(client, 'status', 'Unknown').title(),
            'created_at': client.created_at.strftime('%B %d, %Y') if hasattr(client, 'created_at') else 'N/A',
            
            # Business Information
            'business_name': getattr(client, 'business_name', 'N/A') or 'N/A',
            'business_type': getattr(client, 'business_type', 'N/A') or 'N/A',
            'other_business_type': getattr(client, 'other_business_type', 'N/A') or 'N/A',
            'business_address': getattr(client, 'business_address', 'N/A') or 'N/A',
            'employer': getattr(client, 'employer', 'N/A') or 'N/A',
            'monthly_income': float(getattr(client, 'monthly_income', 0)) if getattr(client, 'monthly_income', 0) else 0,
            'capital_invested': float(getattr(client, 'capital_invested', 0)) if getattr(client, 'capital_invested', 0) else 0,
            'source_of_funds': getattr(client, 'source_of_funds', 'N/A') or 'N/A',
            'expected_turnover': float(getattr(client, 'expected_turnover', 0)) if getattr(client, 'expected_turnover', 0) else 0,
            
            # Reference Information
            'declaration_name': getattr(client, 'declaration_name', 'N/A') or 'N/A',
            'personal_pin': getattr(client, 'personal_pin', 'N/A') or 'N/A',
            'recommender_name': getattr(client, 'recommender_name', 'N/A') or 'N/A',
            'recommender_id': getattr(client, 'recommender_id', 'N/A') or 'N/A',
            'recommender_tel': getattr(client, 'recommender_tel', 'N/A') or 'N/A',
            'recommender_mobile': getattr(client, 'recommender_mobile', 'N/A') or 'N/A',
            'recommender_residence': getattr(client, 'recommender_residence', 'N/A') or 'N/A',
            'guarantor_name': getattr(client, 'guarantor_name', 'N/A') or 'N/A',
            'guarantor_id': getattr(client, 'guarantor_id', 'N/A') or 'N/A',
            'guarantor_tel': getattr(client, 'guarantor_tel', 'N/A') or 'N/A',
            'guarantor_mobile': getattr(client, 'guarantor_mobile', 'N/A') or 'N/A',
            'guarantor_residence': getattr(client, 'guarantor_residence', 'N/A') or 'N/A',
            
            # OPTIMIZED: Lightweight loan statistics
            'credit_score': credit_score,
            'total_borrowed': total_borrowed,
            'total_repaid': total_repaid,
            'active_loans': active_loans,
            'outstanding_amount': outstanding_amount,
            'loans': loans_data,
            'documents': documents,
            
            # OPTIMIZED: Simplified analytics data
            'analytics': {
                'risk_analysis': {
                    'risk_level': 'Low' if credit_score >= 70 else 'Medium' if credit_score >= 50 else 'High',
                    'repayment_rate': round((total_repaid / total_borrowed * 100) if total_borrowed > 0 else 0, 2)
                },
                'profitability': {
                    'total_interest_earned': float(loan_stats['total_interest'] or 0),
                    'profit_margin': round((float(loan_stats['total_interest'] or 0) / total_borrowed * 100) if total_borrowed > 0 else 0, 2)
                },
                'operational_metrics': [
                    {'metric': 'Total Loans', 'value': loan_stats['total_loans'] or 0},
                    {'metric': 'Active Loans', 'value': active_loans},
                    {'metric': 'Repayment Rate', 'value': f"{round((total_repaid / total_borrowed * 100) if total_borrowed > 0 else 0, 1)}%"}
                ],
                'recommendations': [
                    'Monitor repayment patterns closely' if credit_score < 50 else 'Client shows good repayment history',
                    'Consider increasing loan limits' if credit_score >= 70 else 'Maintain current loan limits'
                ],
                'executive_summary': f"Client has {loan_stats['total_loans'] or 0} loans with {active_loans} currently active. Total borrowed: ${total_borrowed:,.2f}, repaid: ${total_repaid:,.2f}.",
                'portfolio_metrics': {
                    'total_loans': loan_stats['total_loans'] or 0,
                    'active_loans': active_loans,
                    'total_principal': total_borrowed,
                    'total_repaid': total_repaid
                },
                'portfolio_trends': {
                    'repayment_trend': 'Stable' if credit_score >= 60 else 'Needs attention',
                    'growth_rate': 'Positive' if total_repaid > total_borrowed * 0.8 else 'Moderate'
                },
                'revenue_metrics': [
                    {'metric': 'Interest Earned', 'value': f"${float(loan_stats['total_interest'] or 0):,.2f}"},
                    {'metric': 'Profit Margin', 'value': f"{round((float(loan_stats['total_interest'] or 0) / total_borrowed * 100) if total_borrowed > 0 else 0, 1)}%"}
                ],
                'revenue_trends': {
                    'monthly_growth': 'Stable',
                    'profitability': 'Good' if float(loan_stats['total_interest'] or 0) > total_borrowed * 0.1 else 'Moderate'
                },
                'risk_metrics': [
                    {'metric': 'Credit Score', 'value': credit_score},
                    {'metric': 'Outstanding Amount', 'value': f"${outstanding_amount:,.2f}"},
                    {'metric': 'Risk Level', 'value': 'Low' if credit_score >= 70 else 'Medium' if credit_score >= 50 else 'High'}
                ],
                'risk_factors': [
                    'High outstanding amount' if outstanding_amount > total_borrowed * 0.5 else 'Manageable debt level',
                    'Low repayment rate' if credit_score < 50 else 'Good repayment history'
                ],
            },
            
            # Charts
            'chart_data': chart_data,
            
            # URLs
            'update_url': request.build_absolute_uri(reverse('users:client_update', kwargs={'client_id': client.id})),
            'delete_url': request.build_absolute_uri(reverse('users:client_delete', kwargs={'client_id': client.id})),
            'report_url': request.build_absolute_uri(reverse('users:client_report', kwargs={'client_id': client.id})),
            'download_report_url': request.build_absolute_uri(reverse('users:client_download_report', kwargs={'client_id': client.id})),
        }
        
        response_data = {'success': True, 'client': client_data}
        
        # Cache the result for 5 minutes (300 seconds)
        cache.set(cache_key, response_data, 300)
        
        return JsonResponse(response_data)
        
    except Exception as e:
        print(f"Error in client_popup view: {str(e)}")
        return JsonResponse({'success': False, 'error': str(e)})


@login_required
@xframe_options_sameorigin
def client_report(request, client_id):
    """Generate comprehensive client report"""
    try:
        client = get_object_or_404(CustomUser, id=client_id, role='borrower')
        
        # Check if this is a report generation request
        generate_report = request.GET.get('generate_report', False)
        download_report = request.GET.get('download', False)
        
        # Get loan statistics
        try:
            active_loans = Loan.objects.filter(borrower=client, status='active').count()
            total_loans = Loan.objects.filter(borrower=client).count()
            total_borrowed = Loan.objects.filter(borrower=client).aggregate(
                total=Sum('principal_amount')
            )['total'] or 0
            # Calculate total repaid from repayments
            total_repaid = Repayment.objects.filter(
                loan__borrower=client
            ).aggregate(total=Sum('amount'))['total'] or 0
            outstanding_amount = total_borrowed - total_repaid
            
            # Get loan history
            loans = Loan.objects.filter(borrower=client).order_by('-created_at')
            
            # Get loan performance metrics
            total_on_time = loans.filter(status='paid', paid_on_time=True).count()
            total_late = loans.filter(status='paid', paid_on_time=False).count()
            total_defaulted = loans.filter(status='defaulted').count()
            
            # Calculate repayment performance
            if total_loans > 0:
                on_time_rate = (total_on_time / total_loans) * 100
                late_rate = (total_late / total_loans) * 100
                default_rate = (total_defaulted / total_loans) * 100
            else:
                on_time_rate = late_rate = default_rate = 0
                
            # Get monthly loan trends
            from datetime import datetime, timedelta
            from django.utils import timezone
            from utils.datetime_utils import get_current_datetime, make_datetime_compatible
            
            # Get repayment data for the last 6 months
            six_months_ago = get_current_datetime() - timedelta(days=180)
            repayments = Repayment.objects.filter(
                loan__borrower=client,
                payment_date__gte=six_months_ago
            ).order_by('payment_date')
            
            # Group repayments by month
            monthly_repayments = {}
            for repayment in repayments:
                month_key = repayment.payment_date.strftime('%B %Y')
                if month_key not in monthly_repayments:
                    monthly_repayments[month_key] = 0
                monthly_repayments[month_key] += float(repayment.amount)
            
            chart_data = {
                'repayment_trend': {
                    'labels': list(monthly_repayments.keys()),
                    'data': list(monthly_repayments.values())
                }
            }
            
        except Exception as e:
            active_loans = total_loans = 0
            total_borrowed = total_repaid = outstanding_amount = 0
            on_time_rate = late_rate = default_rate = 0
            loans = []
            monthly_repayments = {}
            print(f"Error calculating loan stats for client {client.id}: {str(e)}")
        
        # Get credit score
        try:
            credit_score = LoanScoring.objects.get(user=client)
            credit_score_value = credit_score.total_score
            credit_score_details = {
                'payment_history': credit_score.repayment_history_score,
                'income_score': credit_score.income_score,
                'rollover_frequency': credit_score.rollover_frequency_score,
                'employment_stability': credit_score.employment_stability_score,
                'total_score': credit_score.total_score
            }
        except LoanScoring.DoesNotExist:
            credit_score_value = 0
            credit_score_details = {}
        
        # Get document status
        documents = {
            'id_document': bool(client.id_document),
            'selfie': bool(client.selfie),
            'utility_bill': bool(client.utility_bill),
            'bank_statement': bool(client.bank_statement),
            'logbook': bool(client.logbook),
            'title_deed': bool(client.title_deed),
            'signature': bool(client.signature),
        }
        
        # Get recent activities
        activities = AuditLog.objects.filter(
            Q(user=client) | 
            Q(object_id=str(client.id), model_name='CustomUser')
        ).order_by('-created_at')[:10]
        
        context = {
            'client': client,
            'loans': loans,
            'loan_stats': {
                'active_loans': active_loans,
                'total_loans': total_loans,
                'total_borrowed': total_borrowed,
                'total_repaid': total_repaid,
                'outstanding_amount': outstanding_amount,
                'on_time_rate': on_time_rate,
                'late_rate': late_rate,
                'default_rate': default_rate,
            },
            'monthly_trends': monthly_repayments, # Use monthly_repayments for the chart
            'credit_score': credit_score_value,
            'credit_score_details': credit_score_details,
            'documents': documents,
            'activities': activities,
            'report_date': get_current_datetime(),
            'is_report': generate_report,
        }
        
        if download_report:
            # Generate PDF response for download
            response = HttpResponse(content_type='application/pdf')
            response['Content-Disposition'] = f'attachment; filename="client_report_{client.id}_{get_current_datetime().strftime("%Y%m%d_%H%M%S")}.pdf"'
            
            # For now, return a simple text response indicating PDF generation
            # In a real implementation, you would use a library like WeasyPrint or ReportLab
            response.write(f"Client Report for {client.get_full_name()}\n")
            response.write(f"Generated on: {get_current_datetime().strftime('%B %d, %Y at %I:%M %p')}\n\n")
            response.write("This is a placeholder for the PDF report.\n")
            response.write("In a production environment, this would generate a comprehensive PDF report.\n")
            
            return response
        elif generate_report:
            return render(request, 'users/client_report_print.html', context)
        else:
            return render(request, 'users/client_report.html', context)
        
    except Exception as e:
        messages.error(request, f'Error generating report: {str(e)}')
        return redirect('users:client_list')


@login_required
def client_download_report(request, client_id):
    """Download client report as PDF"""
    # Check if user has permission to download client files
    if not request.user.has_permission('clients', 'download'):
        messages.error(request, 'You do not have permission to download client reports.')
        return redirect('users:client_detail', client_id=client_id)
    try:
        client = get_object_or_404(CustomUser, id=client_id, role='borrower')
        
        # Get loan statistics
        try:
            active_loans = Loan.objects.filter(borrower=client, status='active').count()
            total_loans = Loan.objects.filter(borrower=client).count()
            total_borrowed = Loan.objects.filter(borrower=client).aggregate(
                total=Sum('principal_amount')
            )['total'] or 0
            # Calculate total repaid from repayments
            total_repaid = Repayment.objects.filter(
                loan__borrower=client
            ).aggregate(total=Sum('amount'))['total'] or 0
            outstanding_amount = total_borrowed - total_repaid
            
            # Get loan history
            loans = Loan.objects.filter(borrower=client).order_by('-created_at')
        except Exception as e:
            active_loans = 0
            total_loans = 0
            total_borrowed = 0
            total_repaid = 0
            outstanding_amount = 0
            loans = []
            print(f"Error calculating loan stats for client {client.id}: {str(e)}")
        
        # Get credit score
        try:
            credit_score = LoanScoring.objects.get(user=client)
            credit_score_value = credit_score.total_score
            credit_score_details = {
                'payment_history': credit_score.repayment_history_score,
                'income_score': credit_score.income_score,
                'rollover_frequency': credit_score.rollover_frequency_score,
                'employment_stability': credit_score.employment_stability_score,
                'total_score': credit_score.total_score
            }
        except LoanScoring.DoesNotExist:
            credit_score_value = 0
            credit_score_details = {}
        
        # Get document status
        documents = {
            'id_document': bool(client.id_document),
            'selfie': bool(client.selfie),
            'utility_bill': bool(client.utility_bill),
            'bank_statement': bool(client.bank_statement),
            'logbook': bool(client.logbook),
            'title_deed': bool(client.title_deed),
            'signature': bool(client.signature),
        }
        
        context = {
            'client': client,
            'loans': loans,
            'loan_stats': {
                'active_loans': active_loans,
                'total_loans': total_loans,
                'total_borrowed': total_borrowed,
                'total_repaid': total_repaid,
                'outstanding_amount': outstanding_amount,
            },
            'credit_score': credit_score_value,
            'credit_score_details': credit_score_details,
            'documents': documents,
            'report_date': get_current_datetime(),
        }
        
        # Generate PDF response
        response = HttpResponse(content_type='application/pdf')
        response['Content-Disposition'] = f'attachment; filename="client_report_{client.id}_{get_current_datetime().strftime("%Y%m%d_%H%M%S")}.pdf"'
        
        # For now, return a simple text response indicating PDF generation
        # In a real implementation, you would use a library like WeasyPrint or ReportLab
        response.write(f"Client Report for {client.get_full_name()}\n")
        response.write(f"Generated on: {get_current_datetime().strftime('%B %d, %Y at %I:%M %p')}\n\n")
        response.write("This is a placeholder for the PDF report.\n")
        response.write("In a production environment, this would generate a comprehensive PDF report.\n")
        
        return response
        
    except Exception as e:
        messages.error(request, f'Error downloading report: {str(e)}')
        return redirect('users:client_list')


@login_required
def client_documents(request, client_id):
    """View for managing client's KYC documents"""
    # Check if user has permission to access customer documents
    if not request.user.has_permission('customer_documents', 'access'):
        messages.error(request, 'You do not have permission to access customer documents.')
        return redirect('users:client_list')
    
    client = get_object_or_404(CustomUser, id=client_id)
    
    # Check permissions
    if not request.user.is_staff and request.user != client:
        messages.error(request, 'You do not have permission to view these documents')
        return redirect('users:client_list')
    
    # Get documents by type with prefetch for optimization
    documents = Document.objects.filter(
        Q(uploaded_by=client) | Q(shared_with=client)
    ).select_related('uploaded_by').prefetch_related('tags')
    
    context = {
        'client': client,
        'id_documents': documents.filter(document_type='id_document').order_by('-created_at'),
        'selfie_documents': documents.filter(document_type='selfie').order_by('-created_at'),
        'utility_documents': documents.filter(document_type='utility_bill').order_by('-created_at'),
        'bank_documents': documents.filter(document_type='bank_statement').order_by('-created_at'),
    }
    
    return render(request, 'users/client_documents.html', context)

@login_required
def upload_client_document(request, client_id):
    """API endpoint for uploading client documents"""
    # Check if user has permission to upload client documents
    if not request.user.has_permission('clients', 'upload'):
        messages.error(request, 'You do not have permission to upload client documents.')
        return redirect('users:client_detail', client_id=client_id)
    
    if request.method == 'POST':
        client = get_object_or_404(CustomUser, id=client_id)
        
        # Check permissions
        if not request.user.is_staff and request.user != client:
            return JsonResponse({
                'status': 'error',
                'error': 'Permission denied'
            })
        
        try:
            document_type = request.POST.get('document_type')
            description = request.POST.get('description', '')
            file = request.FILES.get('file')
            
            if not all([document_type, file]):
                return JsonResponse({
                    'status': 'error',
                    'error': 'Missing required fields'
                })
            
            # Validate file type
            allowed_types = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf']
            # Use magic if available, otherwise rely on file extension
            if MAGIC_AVAILABLE:
                file_type = magic.from_buffer(file.read(1024), mime=True)
                file.seek(0)  # Reset file pointer after reading
            else:
                # Fallback to checking file extension
                file_name = file.name.lower()
                if file_name.endswith(('.jpg', '.jpeg')):
                    file_type = 'image/jpeg'
                elif file_name.endswith('.png'):
                    file_type = 'image/png'
                elif file_name.endswith('.gif'):
                    file_type = 'image/gif'
                elif file_name.endswith('.pdf'):
                    file_type = 'application/pdf'
                else:
                    file_type = 'unknown'
            
            if file_type not in allowed_types:
                return JsonResponse({
                    'status': 'error',
                    'error': f'Invalid file type. Allowed types: {", ".join(allowed_types)}'
                })
            
            # Create document
            document = Document.objects.create(
                name=file.name,
                file=file,
                document_type=document_type,
                description=description,
                uploaded_by=client,
                mime_type=file_type
            )
            
            # Generate thumbnail for images
            if file_type.startswith('image/'):
                try:
                    img = Image.open(file)
                    img.thumbnail((300, 300))
                    thumb_io = BytesIO()
                    img.save(thumb_io, format='JPEG', quality=85)
                    thumb_name = f'thumb_{file.name}'
                    document.thumbnail.save(thumb_name, ContentFile(thumb_io.getvalue()), save=True)
                except Exception as e:
                    print(f"Error generating thumbnail: {e}")
            
            # Create audit log
            AuditLog.objects.create(
                user=request.user,
                action='create',
                model_name='Document',
                object_id=str(document.id),
                description=f'Uploaded {document_type} document for client {client.get_full_name()}'
            )
            
            # Create notification for admins if staff uploaded (only if notifications are enabled)
            if request.user.is_staff:
                # Check if notifications are enabled
                from utils.models import SystemSetting
                if SystemSetting.get_bool('email_notifications', True):
                    Notification.objects.create(
                        title='New Client Document',
                        message=f'Staff member {request.user.get_full_name()} uploaded a {document_type} for {client.get_full_name()}',
                        priority='medium',
                        user=client
                    )
            
            return JsonResponse({'status': 'success'})
            
        except Exception as e:
            return JsonResponse({
                'status': 'error',
                'error': str(e)
            })
    
    return JsonResponse({
        'status': 'error',
        'error': 'Invalid request method'
    })

@login_required
def admin_confirm_delete(request, admin_id):
    """View for confirming admin deletion"""
    
    # Check if user has admin access
    if not (request.user.is_superuser or request.user.role == 'admin'):
        messages.error(request, 'You do not have permission to manage staff users.')
        return redirect('dashboard')
    admin = get_object_or_404(CustomUser, id=admin_id, is_staff=True)
    
    if request.method == 'POST':
        # Create audit log
        AuditLog.objects.create(
            user=request.user,
            action='delete',
            model_name='CustomUser',
            object_id=str(admin.id),
            description=f'Deactivated admin user: {admin.get_full_name()}'
        )
        
        # Deactivate admin
        admin.is_active = False
        admin.save()
        
        messages.success(request, f'Admin {admin.get_full_name()} has been deactivated')
        return redirect('users:admin_list')
    
    return render(request, 'users/admin_confirm_delete.html', {'admin': admin})

@login_required
def admin_confirm_reactivate(request, admin_id):
    """View for confirming admin reactivation"""
    
    # Check if user has admin access
    if not (request.user.is_superuser or request.user.role == 'admin'):
        messages.error(request, 'You do not have permission to manage staff users.')
        return redirect('dashboard')
    admin = get_object_or_404(CustomUser, id=admin_id, is_staff=True)
    
    if request.method == 'POST':
        # Create audit log
        AuditLog.objects.create(
            user=request.user,
            action='update',
            model_name='CustomUser',
            object_id=str(admin.id),
            description=f'Reactivated admin user: {admin.get_full_name()}'
        )
        
        # Reactivate admin
        admin.is_active = True
        admin.save()
        
        messages.success(request, f'Admin {admin.get_full_name()} has been reactivated')
        return redirect('users:admin_list')
    
    return render(request, 'users/admin_confirm_reactivate.html', {'admin': admin})


@login_required
def user_access_logs(request):
    """View user access logs and audit trails"""
    
    # Check if user has admin access
    if not (request.user.is_superuser or request.user.role == 'admin'):
        messages.error(request, 'You do not have permission to view access logs.')
        return redirect('dashboard')
    
    # Get filter parameters
    selected_user = request.GET.get('user')
    selected_action = request.GET.get('action')
    selected_module = request.GET.get('module')
    date_range = request.GET.get('date_range', 'all')
    
    # Build query
    from users.models import UserAccessLog
    from datetime import datetime, timedelta
    from django.utils import timezone
    
    logs = UserAccessLog.objects.select_related('user').all()
    
    # Apply filters
    if selected_user:
        logs = logs.filter(user_id=selected_user)
    if selected_action:
        logs = logs.filter(action=selected_action)
    if selected_module:
        logs = logs.filter(module=selected_module)
    
    # Date range filter
    if date_range == 'today':
        logs = logs.filter(accessed_at__date=timezone.now().date())
    elif date_range == 'week':
        week_ago = timezone.now() - timedelta(days=7)
        logs = logs.filter(accessed_at__gte=week_ago)
    elif date_range == 'month':
        month_ago = timezone.now() - timedelta(days=30)
        logs = logs.filter(accessed_at__gte=month_ago)
    
    # Calculate stats
    total_logs = UserAccessLog.objects.count()
    active_users = UserAccessLog.objects.values('user').distinct().count()
    access_denied = UserAccessLog.objects.filter(action='access_denied').count()
    today_activity = UserAccessLog.objects.filter(accessed_at__date=timezone.now().date()).count()
    
    # Pagination
    paginator = Paginator(logs.order_by('-accessed_at'), 50)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    
    # Get users for filter dropdown
    users = CustomUser.objects.filter(is_staff=True).order_by('first_name', 'last_name')
    
    context = {
        'logs': page_obj,
        'users': users,
        'selected_user': selected_user,
        'selected_action': selected_action,
        'selected_module': selected_module,
        'date_range': date_range,
        'total_logs': total_logs,
        'active_users': active_users,
        'access_denied': access_denied,
        'today_activity': today_activity,
    }
    
    return render(request, 'users/access_logs.html', context)


@login_required
def user_permissions(request, user_id):
    """Manage user permissions with comprehensive module system"""
    
    # Check if user has admin access
    if not (request.user.is_superuser or request.user.role == 'admin'):
        messages.error(request, 'You do not have permission to manage user permissions.')
        return redirect('main_dashboard')
    
    user = get_object_or_404(CustomUser, id=user_id)
    
    if request.method == 'POST':
        # Update permissions using the comprehensive module system
        from users.models import UserPermission
        
        # Get all module choices from the model
        module_choices = [
            ('dashboard', 'Dashboard'),
            ('clients', 'Clients'),
            ('loans', 'Loans'),
            ('repayments', 'All Repayments'),
            ('portfolio', 'Portfolio'),
            ('reports_statements', 'Reports & Statements'),
            ('documents', 'Documents'),
            ('customer_documents', 'Customer Documents'),
            ('payment_receipts', 'Payment Receipts'),
            ('notifications', 'Notifications'),
            ('settings', 'Settings'),
            ('branch_settings', 'Branch Settings'),
            ('system_settings', 'System Settings'),
        ]
        
        action_choices = [
            ('view', 'View'),
            ('create', 'Create'),
            ('edit', 'Edit'),
            ('delete', 'Delete'),
            ('approve', 'Approve'),
            ('reject', 'Reject'),
            ('export', 'Export'),
            ('import', 'Import'),
            ('manage', 'Manage'),
        ]
        
        # Clear existing user permissions for this user
        UserPermission.objects.filter(user=user).delete()
        
        # Process form data
        for module_code, module_name in module_choices:
            for action_code, action_name in action_choices:
                field_name = f'perm_{module_code}_{action_code}'
                is_allowed = request.POST.get(field_name) == 'on'
                
                # Only create permission if it differs from role default
                try:
                    from users.models import RolePermission
                    role_perm = RolePermission.objects.get(
                        role=user.role,
                        module=module_code,
                        action=action_code
                    )
                    role_default = role_perm.is_allowed
                except RolePermission.DoesNotExist:
                    role_default = False
                
                # Create user permission if it differs 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=request.user,
                        reason=f'Custom permission override for {module_name} - {action_name}'
                    )
        
        # Log the permission update
        request.user.log_access(
            action='update_permissions',
            module='users',
            object_type='CustomUser',
            object_id=str(user.id),
            description=f'Updated comprehensive permissions for {user.get_full_name()}',
            request=request
        )
        
        messages.success(request, f'Permissions updated for {user.get_full_name()}')
        return redirect('users:admin_list')
    
    # Get current permissions with comprehensive system
    permissions = user.get_effective_permissions()
    
    # Organize permissions by main categories
    organized_permissions = {
        'Dashboard': {},
        'Clients Management': {},
        'Loans Management': {},
        'Repayments & Payments': {},
        'Portfolio Management': {},
        'Reports & Analytics': {},
        'Documents & KYC': {},
        'Notifications & Communication': {},
        'Settings & Administration': {},
    }
    
    # Map modules to categories
    module_categories = {
        'dashboard': 'Dashboard',
        'dashboard_overview': 'Dashboard',
        'dashboard_metrics': 'Dashboard',
        'dashboard_charts': 'Dashboard',
        'dashboard_recent_activities': 'Dashboard',
        'dashboard_quick_actions': 'Dashboard',
        'dashboard_loan_summary': 'Dashboard',
        'dashboard_collection_summary': 'Dashboard',
        'dashboard_branch_performance': 'Dashboard',
        'dashboard_alerts': 'Dashboard',
        
        'clients': 'Clients Management',
        'clients_view_list': 'Clients Management',
        'clients_search_filter': 'Clients Management',
        'clients_create_new': 'Clients Management',
        'clients_edit_profile': 'Clients Management',
        'clients_delete_client': 'Clients Management',
        'clients_view_details': 'Clients Management',
        'clients_loan_history': 'Clients Management',
        'clients_payment_history': 'Clients Management',
        'clients_kyc_documents': 'Clients Management',
        'clients_assign_portfolio': 'Clients Management',
        'clients_registration_fee': 'Clients Management',
        'clients_status_change': 'Clients Management',
        'clients_export_data': 'Clients Management',
        'clients_bulk_actions': 'Clients Management',
        
        'loans': 'Loans Management',
        'loans_view_list': 'Loans Management',
        'loans_search_filter': 'Loans Management',
        'loans_create_application': 'Loans Management',
        'loans_edit_application': 'Loans Management',
        'loans_delete_loan': 'Loans Management',
        'loans_approve_application': 'Loans Management',
        'loans_reject_application': 'Loans Management',
        'loans_disburse_funds': 'Loans Management',
        'loans_view_details': 'Loans Management',
        'loans_amortization_schedule': 'Loans Management',
        'loans_rollover_loan': 'Loans Management',
        'loans_calculate_interest': 'Loans Management',
        'loans_generate_receipt': 'Loans Management',
        'loans_modify_terms': 'Loans Management',
        'loans_close_loan': 'Loans Management',
        'loans_export_data': 'Loans Management',
        
        'repayments': 'Repayments & Payments',
        'repayments_view_list': 'Repayments & Payments',
        'repayments_search_filter': 'Repayments & Payments',
        'repayments_record_payment': 'Repayments & Payments',
        'repayments_edit_payment': 'Repayments & Payments',
        'repayments_delete_payment': 'Repayments & Payments',
        'repayments_verify_payment': 'Repayments & Payments',
        'repayments_reconcile_mpesa': 'Repayments & Payments',
        'repayments_generate_receipt': 'Repayments & Payments',
        'repayments_bulk_import': 'Repayments & Payments',
        'repayments_export_data': 'Repayments & Payments',
        'repayments_view_analytics': 'Repayments & Payments',
        'payment_receipts': 'Repayments & Payments',
        'receipts_view_all': 'Repayments & Payments',
        'receipts_generate_new': 'Repayments & Payments',
        'receipts_edit_existing': 'Repayments & Payments',
        'receipts_delete_receipt': 'Repayments & Payments',
        'receipts_print_receipt': 'Repayments & Payments',
        'receipts_download_pdf': 'Repayments & Payments',
        'receipts_email_client': 'Repayments & Payments',
        'receipts_bulk_generate': 'Repayments & Payments',
        'receipts_template_manage': 'Repayments & Payments',
        
        'portfolio': 'Portfolio Management',
        'portfolio_view_overview': 'Portfolio Management',
        'portfolio_manager_stats': 'Portfolio Management',
        'portfolio_performance_metrics': 'Portfolio Management',
        'portfolio_client_assignments': 'Portfolio Management',
        'portfolio_reassign_clients': 'Portfolio Management',
        'portfolio_view_analytics': 'Portfolio Management',
        'portfolio_generate_reports': 'Portfolio Management',
        'portfolio_target_tracking': 'Portfolio Management',
        
        'reports_statements': 'Reports & Analytics',
        'reports_view_dashboard': 'Reports & Analytics',
        'reports_loans_due': 'Reports & Analytics',
        'reports_delinquent_loans': 'Reports & Analytics',
        'reports_arrears_analysis': 'Reports & Analytics',
        'reports_processing_fees': 'Reports & Analytics',
        'reports_interest_income': 'Reports & Analytics',
        'reports_registration_fees': 'Reports & Analytics',
        'reports_customer_requests': 'Reports & Analytics',
        'reports_collection_summary': 'Reports & Analytics',
        'reports_branch_performance': 'Reports & Analytics',
        'reports_export_all': 'Reports & Analytics',
        'reports_schedule_automated': 'Reports & Analytics',
        'statements_generate_loan': 'Reports & Analytics',
        'statements_generate_client': 'Reports & Analytics',
        'statements_download_pdf': 'Reports & Analytics',
        'statements_email_client': 'Reports & Analytics',
        
        'documents': 'Documents & KYC',
        'customer_documents': 'Documents & KYC',
        'documents_view_library': 'Documents & KYC',
        'documents_upload_files': 'Documents & KYC',
        'documents_download_files': 'Documents & KYC',
        'documents_delete_files': 'Documents & KYC',
        'documents_organize_folders': 'Documents & KYC',
        'documents_search_content': 'Documents & KYC',
        'documents_share_access': 'Documents & KYC',
        'documents_version_control': 'Documents & KYC',
        'customer_docs_view_all': 'Documents & KYC',
        'customer_docs_upload_kyc': 'Documents & KYC',
        'customer_docs_verify_identity': 'Documents & KYC',
        'customer_docs_approve_kyc': 'Documents & KYC',
        'customer_docs_reject_kyc': 'Documents & KYC',
        'customer_docs_request_additional': 'Documents & KYC',
        'customer_docs_download_files': 'Documents & KYC',
        'customer_docs_compliance_check': 'Documents & KYC',
        
        'notifications': 'Notifications & Communication',
        'notifications_view_inbox': 'Notifications & Communication',
        'notifications_send_individual': 'Notifications & Communication',
        'notifications_send_bulk': 'Notifications & Communication',
        'notifications_manage_templates': 'Notifications & Communication',
        'notifications_configure_settings': 'Notifications & Communication',
        'notifications_view_history': 'Notifications & Communication',
        'notifications_manage_channels': 'Notifications & Communication',
        
        'settings': 'Settings & Administration',
        'branch_settings': 'Settings & Administration',
        'system_settings': 'Settings & Administration',
        'settings_view_general': 'Settings & Administration',
        'settings_edit_system': 'Settings & Administration',
        'settings_manage_users': 'Settings & Administration',
        'settings_configure_permissions': 'Settings & Administration',
        'settings_backup_restore': 'Settings & Administration',
        'settings_integration_config': 'Settings & Administration',
        'settings_audit_logs': 'Settings & Administration',
        'branch_view_info': 'Settings & Administration',
        'branch_edit_details': 'Settings & Administration',
        'branch_manage_staff': 'Settings & Administration',
        'branch_configure_mpesa': 'Settings & Administration',
        'branch_view_performance': 'Settings & Administration',
        'branch_manage_targets': 'Settings & Administration',
        'system_database_management': 'Settings & Administration',
        'system_server_monitoring': 'Settings & Administration',
        'system_security_settings': 'Settings & Administration',
        'system_maintenance_mode': 'Settings & Administration',
        'system_api_management': 'Settings & Administration',
        'system_integration_logs': 'Settings & Administration',
    }
    
    # Organize permissions by category
    for module, actions in permissions.items():
        category = module_categories.get(module, 'Other')
        if category not in organized_permissions:
            organized_permissions[category] = {}
        organized_permissions[module] = actions
    
    context = {
        'user': user,
        'permissions': organized_permissions,
        'module_categories': module_categories,
    }
    
    return render(request, 'users/user_permissions.html', context)


@login_required
@portfolio_access_required
def client_list_ajax(request):
    """AJAX endpoint for client list with filters"""
    try:
        # Get selected branch from session
        selected_branch_id = request.session.get('selected_branch_id')
        
        # Ensure branch selection is always available
        if not selected_branch_id and request.user.is_authenticated:
            if request.user.role == 'admin':
                # For admin users, default to main branch if no selection
                main_branch = Branch.objects.filter(is_main_branch=True, is_active=True).first()
                if main_branch:
                    selected_branch_id = str(main_branch.id)
                    request.session['selected_branch_id'] = selected_branch_id
            elif request.user.branch:
                # For non-admin users, use their assigned branch
                selected_branch_id = str(request.user.branch.id)
                request.session['selected_branch_id'] = selected_branch_id
        
        # Get filter parameters
        search = request.GET.get('search', '').strip()
        status_filter = request.GET.get('status', 'all')
        business_type_filter = request.GET.get('business_type', 'all')
        sort_by = request.GET.get('sort_by', 'first_name')
        sort_order = request.GET.get('sort_order', 'asc')
        
        # Start with all clients, excluding rejected ones
        clients = CustomUser.objects.filter(role='borrower').exclude(rejected_at__isnull=False)
        
        # Apply portfolio-based access control for staff members
        if request.user.role in ['loan_officer', 'team_leader'] and not request.user.is_superuser:
            # Staff members can only see their assigned borrowers
            clients = clients.filter(portfolio_manager=request.user)
        elif request.user.role in ['secretary', 'auditor'] and not request.user.is_superuser:
            # Secretaries and auditors can only see borrowers from their branch
            if request.user.branch:
                clients = clients.filter(branch=request.user.branch)
        
        # Apply branch filtering - now always has a branch selected
        if selected_branch_id:
            clients = clients.filter(branch_id=selected_branch_id)
        # No branch selected — show all clients regardless of branch assignment
        
        # Apply search filter
        if search:
            clients = clients.filter(
                Q(first_name__icontains=search) |
                Q(last_name__icontains=search) |
                Q(email__icontains=search) |
                Q(phone_number__icontains=search) |
                Q(business_name__icontains=search) |
                Q(id_number__icontains=search)
            )
        
        # Apply status filter
        if status_filter != 'all':
            clients = clients.filter(status=status_filter)
        
        # Apply business type filter
        if business_type_filter != 'all':
            clients = clients.filter(business_type=business_type_filter)
        
        # Apply sorting
        if sort_by == 'first_name':
            if sort_order == 'desc':
                clients = clients.order_by('-first_name', '-last_name')
            else:
                clients = clients.order_by('first_name', 'last_name')
        elif sort_by == 'last_name':
            if sort_order == 'desc':
                clients = clients.order_by('-last_name', '-first_name')
            else:
                clients = clients.order_by('last_name', 'first_name')
        elif sort_by == 'business_name':
            if sort_order == 'desc':
                clients = clients.order_by('-business_name')
            else:
                clients = clients.order_by('business_name')
        elif sort_by == 'status':
            if sort_order == 'desc':
                clients = clients.order_by('-status')
            else:
                clients = clients.order_by('status')
        elif sort_by == 'created_at':
            if sort_order == 'desc':
                clients = clients.order_by('-created_at')
            else:
                clients = clients.order_by('created_at')
        else:
            # Default sorting by first name ascending
            clients = clients.order_by('first_name', 'last_name')
        
        # Annotate with loan statistics
        # Note: Cannot annotate total_repaid from loan__amount_paid as it's a property
        clients = clients.annotate(
            active_loans=Count('loan', filter=Q(loan__status='active')),
            total_borrowed=Coalesce(Sum('loan__principal_amount'), 0)
        )
        
        # Render the table HTML
        from django.template.loader import render_to_string
        html = render_to_string('users/client_list_table.html', {
            'clients': clients,
            'request': request
        }, request=request)
        
        return JsonResponse({
            'success': True,
            'html': html,
            'count': clients.count()
        })
        
    except Exception as e:
        return JsonResponse({
            'success': False,
            'error': str(e)
        })


@login_required
def api_search_clients(request):
    """API endpoint for searching clients"""
    from django.http import JsonResponse
    
    query = request.GET.get('q', '').strip()
    
    # Get all active clients
    clients = CustomUser.objects.filter(
        role='borrower',
        is_active=True
    ).order_by('first_name', 'last_name')
    
    # If there's a search query, filter the results
    if query:
        if len(query) < 2:
            return JsonResponse({'clients': []})
        
        clients = clients.filter(
            Q(first_name__icontains=query) |
            Q(last_name__icontains=query) |
            Q(email__icontains=query) |
            Q(phone_number__icontains=query) |
            Q(id_number__icontains=query)
        )[:10]  # Limit search results to 10
    else:
        # Return all clients (limit to 100 for performance)
        clients = clients[:100]
    
    # Format response
    clients_data = []
    for client in clients:
        clients_data.append({
            'id': str(client.id),
            'full_name': client.get_full_name(),
            'email': client.email,
            'phone_number': client.phone_number,
            'id_number': client.id_number,
        })
    
    return JsonResponse({'clients': clients_data})


# Add this function to check if user is admin
def is_admin(user):
    return user.is_authenticated and user.role == 'admin'


@login_required
@admin_required
def pending_clients(request):
    """List clients pending approval"""
    # Check if user has permission to access clients
    if not request.user.has_permission('clients', 'access'):
        messages.error(request, 'You do not have permission to view pending clients.')
        return redirect('users:client_list')
    try:
        # Get selected branch from session
        selected_branch_id = request.session.get('selected_branch_id')
        
        # Ensure branch selection is always available
        if not selected_branch_id and request.user.is_authenticated:
            if request.user.is_staff:
                # For staff users, default to main branch if no selection
                main_branch = Branch.objects.filter(is_main_branch=True, is_active=True).first()
                if main_branch:
                    selected_branch_id = str(main_branch.id)
                    request.session['selected_branch_id'] = selected_branch_id
            elif request.user.branch:
                # For non-staff users, use their assigned branch
                selected_branch_id = str(request.user.branch.id)
                request.session['selected_branch_id'] = selected_branch_id
        
        # Get filter parameters
        search = request.GET.get('search', '')
        
        # Base queryset with branch filtering
        # Only show pending clients - those awaiting approval
        pending_clients_qs = CustomUser.objects.filter(
            role='borrower', 
            status='pending_approval',
            rejected_at__isnull=True  # Only clients that haven't been rejected
        ).select_related()
        
        # Apply branch filtering
        if selected_branch_id:
            pending_clients_qs = pending_clients_qs.filter(branch_id=selected_branch_id)
        # No branch selected — show all pending clients regardless of branch
        
        # Apply search filter
        if search:
            pending_clients_qs = pending_clients_qs.filter(
                Q(first_name__icontains=search) |
                Q(last_name__icontains=search) |
                Q(business_name__icontains=search) |
                Q(id_number__icontains=search) |
                Q(phone_number__icontains=search) |
                Q(email__icontains=search)
            )
        
        # Order by most recent
        pending_clients_qs = pending_clients_qs.order_by('-date_joined')
        
        # Get all branches for filter
        branches = Branch.objects.filter(is_active=True).order_by('name')
        
        # Pagination
        paginator = Paginator(pending_clients_qs, 25)
        page = request.GET.get('page')
        try:
            clients = paginator.page(page)
        except:
            clients = paginator.page(1)
        
        context = {
            'clients': clients,
            'search': search,
            'branches': branches,
            'selected_branch_id': selected_branch_id,
            'total_count': pending_clients_qs.count(),
        }
        
        return render(request, 'users/pending_clients.html', context)
        
    except Exception as e:
        messages.error(request, f'Error loading pending clients: {str(e)}')
        return redirect('users:client_list')


@login_required
@admin_required
def approve_client(request, client_id):
    """Approve a pending client"""
    # Check if user has permission to approve clients
    if not request.user.has_permission('clients', 'approve'):
        messages.error(request, 'You do not have permission to approve clients.')
        return redirect('users:client_list')
    
    if request.method == 'POST':
        try:
            client = get_object_or_404(CustomUser, id=client_id, role='borrower', status='pending_approval')
            
            # Get the reason for approval from the form if provided
            approval_notes = request.POST.get('approval_notes', '')
            
            # Update client status to active
            client.status = 'active'
            client.is_active = True
            client.is_verified = True
            client.verification_date = timezone.now()
            client.verified_by = request.user
            
            # Save approval information
            client.approved_by = request.user
            client.approved_at = timezone.now()
            if approval_notes:
                client.approval_reason = approval_notes
            
            # Clear any previous rejection info
            client.rejected_by = None
            client.rejected_at = None
            client.rejection_reason = ''
            
            # Save the client - ensure all fields are updated
            client.save()
            
            # Double-verify with direct update
            CustomUser.objects.filter(id=client.id).update(
                status='active',
                is_active=True,
                is_verified=True,
                verification_date=timezone.now(),
                verified_by=request.user,
                approved_by=request.user,
                approved_at=timezone.now(),
                rejected_by=None,
                rejected_at=None,
                rejection_reason=''
            )
            
            # Refresh to get latest state
            client.refresh_from_db()
            
            # Create audit log
            AuditLog.objects.create(
                user=request.user,
                action='approve',
                model_name='CustomUser',
                object_id=str(client.id),
                description=f'Approved client: {client.get_full_name()}'
            )
            
            messages.success(request, f'Client {client.get_full_name()} has been approved successfully.')
            
            # Create notification for the client
            if approval_notes:
                Notification.objects.create(
                    user=client,
                    title='Client Registration Approved',
                    message=f'Your client registration has been approved. {approval_notes}',
                    notification_type='success'
                )
            else:
                Notification.objects.create(
                    user=client,
                    title='Client Registration Approved',
                    message='Your client registration has been approved.',
                    notification_type='success'
                )
            
        except Exception as e:
            messages.error(request, f'Error approving client: {str(e)}')
    
    return redirect('users:pending_clients')


@login_required
@admin_required
@transaction.atomic
def reject_client(request, client_id):
    """Reject a pending client"""
    # Check if user has permission to reject clients
    if not request.user.has_permission('clients', 'reject'):
        messages.error(request, 'You do not have permission to reject clients.')
        return redirect('users:client_list')
    if request.method == 'POST':
        try:
            # Allow rejecting any borrower, not just pending ones
            client = get_object_or_404(CustomUser, id=client_id, role='borrower')
            
            # Get the reason for rejection from the form
            rejection_reason = request.POST.get('rejection_reason', '')
            
            if not rejection_reason:
                messages.error(request, 'Please provide a reason for rejection.')
                return redirect('users:pending_clients')
            
            # Get the current time
            now = timezone.now()
            
            # Update client with rejection information using direct update to ensure atomic operation
            updated_count = CustomUser.objects.filter(id=client.id).update(
                status='inactive',
                is_active=False,
                rejected_by=request.user,
                rejected_at=now,
                rejection_reason=rejection_reason
            )
            
            if updated_count == 0:
                messages.error(request, 'Failed to reject client. Please try again.')
                return redirect('users:pending_clients')
            
            # Refresh to get latest state
            client.refresh_from_db()
            
            # Verify the update worked
            if client.rejected_at is None:
                messages.error(request, 'Rejection failed to save. Please try again.')
                return redirect('users:pending_clients')
            
            # Create audit log
            AuditLog.objects.create(
                user=request.user,
                action='reject',
                model_name='CustomUser',
                object_id=str(client.id),
                description=f'Rejected client: {client.get_full_name()}. Reason: {rejection_reason}'
            )
            
            messages.success(request, f'Client {client.get_full_name()} has been rejected.')
            
            # Create notification for the client
            Notification.objects.create(
                user=client,
                title='Client Registration Rejected',
                message=f'Your client registration has been rejected. Reason: {rejection_reason}',
                notification_type='error'
            )
            
        except Exception as e:
            import traceback
            traceback.print_exc()
            messages.error(request, f'Error rejecting client: {str(e)}')
    
    return redirect('users:pending_clients')


@login_required
@admin_required
def bulk_approve_clients(request):
    """Bulk approve multiple pending clients"""
    # Check if user has permission to approve clients
    if not request.user.has_permission('clients', 'approve'):
        messages.error(request, 'You do not have permission to approve clients.')
        return redirect('users:client_list')
    if request.method == 'POST':
        try:
            client_ids = request.POST.getlist('client_ids')
            
            if not client_ids:
                messages.warning(request, 'No clients selected for approval.')
                return redirect('users:pending_clients')
            
            # Get clients that are pending approval
            clients = CustomUser.objects.filter(
                id__in=client_ids,
                role='borrower',
                status='pending_approval'
            )
            
            approved_count = 0
            for client in clients:
                client.status = 'active'
                client.is_active = True
                client.is_verified = True
                client.verification_date = timezone.now()
                client.verified_by = request.user
                client.approved_by = request.user
                client.approved_at = timezone.now()
                
                # Clear any previous rejection info
                client.rejected_by = None
                client.rejected_at = None
                client.rejection_reason = ''
                
                client.save(update_fields=['status', 'is_active', 'is_verified', 'verification_date', 'verified_by', 'approved_by', 'approved_at', 'rejected_by', 'rejected_at', 'rejection_reason'])
                
                # Create audit log
                AuditLog.objects.create(
                    user=request.user,
                    action='approve',
                    model_name='CustomUser',
                    object_id=str(client.id),
                    description=f'Bulk approved client: {client.get_full_name()}'
                )
                
                approved_count += 1
            
            messages.success(request, f'{approved_count} client(s) approved successfully.')
            
        except Exception as e:
            messages.error(request, f'Error bulk approving clients: {str(e)}')
    
    return redirect('users:pending_clients')


@login_required
@admin_required
def rejected_clients(request):
    """List clients that were rejected"""
    # Check if user has permission to access clients
    if not request.user.has_permission('clients', 'access'):
        messages.error(request, 'You do not have permission to view rejected clients.')
        return redirect('users:client_list')
    try:
        # Get selected branch from session
        selected_branch_id = request.session.get('selected_branch_id')
        
        # Ensure branch selection is always available
        if not selected_branch_id and request.user.is_authenticated:
            if request.user.is_staff:
                main_branch = Branch.objects.filter(is_main_branch=True, is_active=True).first()
                if main_branch:
                    selected_branch_id = str(main_branch.id)
                    request.session['selected_branch_id'] = selected_branch_id
            elif request.user.branch:
                selected_branch_id = str(request.user.branch.id)
                request.session['selected_branch_id'] = selected_branch_id
        
        # Get filter parameters
        search = request.GET.get('search', '')
        
        # Base queryset - get rejected clients (clients with rejected_at set)
        rejected_clients_qs = CustomUser.objects.filter(
            role='borrower',
            rejected_at__isnull=False  # Only clients that have been rejected
        ).select_related()
        
        # Apply branch filtering
        if selected_branch_id:
            rejected_clients_qs = rejected_clients_qs.filter(branch_id=selected_branch_id)
        # No branch selected — show all rejected clients regardless of branch
        
        # Apply search filter
        if search:
            rejected_clients_qs = rejected_clients_qs.filter(
                Q(first_name__icontains=search) |
                Q(last_name__icontains=search) |
                Q(business_name__icontains=search) |
                Q(id_number__icontains=search) |
                Q(phone_number__icontains=search) |
                Q(email__icontains=search)
            )
        
        # Order by most recent rejection
        rejected_clients_qs = rejected_clients_qs.order_by('-rejected_at') if hasattr(CustomUser._meta.get_field('rejected_at'), 'name') else rejected_clients_qs.order_by('-date_joined')
        
        # Get all branches for filter
        branches = Branch.objects.filter(is_active=True).order_by('name')
        
        # Pagination
        paginator = Paginator(rejected_clients_qs, 25)
        page = request.GET.get('page')
        try:
            clients = paginator.page(page)
        except:
            clients = paginator.page(1)
        
        context = {
            'clients': clients,
            'search': search,
            'branches': branches,
            'selected_branch_id': selected_branch_id,
            'total_count': rejected_clients_qs.count(),
        }
        
        return render(request, 'users/rejected_clients.html', context)
        
    except Exception as e:
        messages.error(request, f'Error loading rejected clients: {str(e)}')
        return redirect('users:client_list')

@login_required
@user_passes_test(is_admin)
def branch_list(request):
    """List all branches"""
    branches = Branch.objects.all()
    return render(request, 'users/branch_list.html', {'branches': branches})

@login_required
@user_passes_test(is_admin)
def branch_create(request):
    """Create a new branch"""
    if request.method == 'POST':
        name = request.POST.get('name')
        code = request.POST.get('code')
        address = request.POST.get('address')
        phone_number = request.POST.get('phone_number')
        email = request.POST.get('email')
        is_main_branch = request.POST.get('is_main_branch') == 'on'
        
        # M-Pesa configuration - only shortcode is configurable
        mpesa_shortcode = request.POST.get('mpesa_shortcode', '').strip() or None
        
        branch = Branch.objects.create(
            name=name,
            code=code,
            address=address,
            phone_number=phone_number,
            email=email,
            is_main_branch=is_main_branch,
            mpesa_shortcode=mpesa_shortcode
        )
        
        messages.success(request, f'Branch {branch.name} created successfully.')
        return redirect('users:branch_list')
    
    return render(request, 'users/branch_form.html')

@login_required
@user_passes_test(is_admin)
def branch_update(request, pk):
    """Update an existing branch"""
    branch = get_object_or_404(Branch, pk=pk)
    
    if request.method == 'POST':
        branch.name = request.POST.get('name')
        branch.code = request.POST.get('code')
        branch.address = request.POST.get('address')
        branch.phone_number = request.POST.get('phone_number')
        branch.email = request.POST.get('email')
        branch.is_main_branch = request.POST.get('is_main_branch') == 'on'
        branch.is_active = request.POST.get('is_active') == 'on'
        
        # M-Pesa configuration - only shortcode is configurable
        branch.mpesa_shortcode = request.POST.get('mpesa_shortcode', '').strip() or None
        
        branch.save()
        
        messages.success(request, f'Branch {branch.name} updated successfully.')
        return redirect('users:branch_list')
    
    return render(request, 'users/branch_form.html', {'branch': branch})

@login_required
@user_passes_test(is_admin)
def switch_branch(request, branch_id):
    """Switch the current active branch for admin users"""
    try:
        branch = Branch.objects.get(pk=branch_id)
        # Check if user has access to this branch
        if request.user.role == 'admin' or request.user.branch_id == branch_id or branch in request.user.accessible_branches.all():
            request.session['selected_branch_id'] = str(branch_id)
            # Ensure session is saved
            request.session.save()
            messages.success(request, f'Switched to {branch.name}')
        else:
            messages.error(request, 'You do not have access to this branch')
    except Branch.DoesNotExist:
        messages.error(request, 'Invalid branch selected')
    
    # Redirect back to the referring page or dashboard
    return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/dashboard/'))
