import json
from django.core.serializers.json import DjangoJSONEncoder
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.db.models import Sum, Count, Q, F, Avg
from datetime import datetime, timedelta
from decimal import Decimal, DecimalException
from .models import (
    LoanProduct, LoanApplication, Loan, Repayment, 
    RolloverRequest, MpesaTransaction
)
from users.models import CustomUser
from reports.models import LoanScoring
from utils.models import AuditLog, SystemSetting, Notification
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.http import JsonResponse, HttpResponse
from django.db import models, IntegrityError
import math
import os


@login_required
def new_application(request):
    """Create a new loan application with improved client handling"""
    try:
        # Get client if specified
        client_id = request.GET.get('client_id')
        client = None
        if client_id:
            try:
                client = get_object_or_404(CustomUser, pk=client_id, role='borrower')
            except:
                client = None
        
        # Get all active loan products
        loan_products = LoanProduct.objects.filter(is_active=True).order_by(
            models.Case(
                models.When(product_type='boost', then=models.Value(1)),
                models.When(product_type='boost_plus', then=models.Value(2)),
                models.When(product_type='mwamba', then=models.Value(3)),
                models.When(product_type='imara', then=models.Value(4)),
                default=models.Value(4)
            ),
            'name'
        )
        
        if request.method == 'POST':
            try:
                # Get form data with detailed validation
                client_id = request.POST.get('client_id')
                print(f"DEBUG: Received client_id: {client_id}")  # Debug logging
                
                if not client_id or client_id == '':
                    return JsonResponse({
                        'status': 'error', 
                        'message': 'Please select a client from the dropdown'
                    }, status=400)

                loan_product_id = request.POST.get('loan_product')
                if not loan_product_id:
                    return JsonResponse({
                        'status': 'error', 
                        'message': 'Please select a loan product'
                    }, status=400)

                try:
                    requested_amount = Decimal(request.POST.get('amount', '0'))
                    if requested_amount <= 0:
                        return JsonResponse({
                            'status': 'error', 
                            'message': 'Please enter a valid loan amount greater than 0'
                        }, status=400)
                except (TypeError, ValueError, DecimalException):
                    return JsonResponse({
                        'status': 'error', 
                        'message': 'Please enter a valid loan amount'
                    }, status=400)

                try:
                    requested_duration = int(request.POST.get('duration', '0'))
                    if requested_duration <= 0:
                        return JsonResponse({
                            'status': 'error', 
                            'message': 'Please enter a valid duration greater than 0'
                        }, status=400)
                except (TypeError, ValueError):
                    return JsonResponse({
                        'status': 'error', 
                        'message': 'Please enter a valid duration'
                    }, status=400)

                purpose = request.POST.get('purpose', '').strip()
                if not purpose:
                    return JsonResponse({
                        'status': 'error', 
                        'message': 'Please enter the loan purpose'
                    }, status=400)

                repayment_method = request.POST.get('repayment_method')
                if not repayment_method:
                    return JsonResponse({
                        'status': 'error', 
                        'message': 'Please select a repayment method'
                    }, status=400)

                # Handle disbursement date
                disbursement_date_str = request.POST.get('disbursement_date')
                if disbursement_date_str:
                    try:
                        disbursement_date = datetime.strptime(disbursement_date_str, '%Y-%m-%d')
                        # Check if user is trying to set a past date
                        if disbursement_date.date() < datetime.now().date():
                            if not request.user.is_staff and not request.user.is_superuser:
                                return JsonResponse({
                                    'status': 'error', 
                                    'message': 'Only administrators can set past disbursement dates'
                                }, status=403)
                    except ValueError:
                        return JsonResponse({
                            'status': 'error', 
                            'message': 'Invalid disbursement date format'
                        }, status=400)
                else:
                    disbursement_date = datetime.now()

                # Get loan product and client with better error handling
                try:
                    loan_product = LoanProduct.objects.get(pk=loan_product_id)
                except LoanProduct.DoesNotExist:
                    return JsonResponse({
                        'status': 'error', 
                        'message': 'Selected loan product not found'
                    }, status=400)
                
                try:
                    client = CustomUser.objects.get(pk=client_id, role='borrower')
                    print(f"DEBUG: Found client: {client.get_full_name()}")  # Debug logging
                except CustomUser.DoesNotExist:
                    return JsonResponse({
                        'status': 'error', 
                        'message': 'Selected client not found or is not a borrower'
                    }, status=400)
                
                # Check client status
                if hasattr(client, 'status'):
                    if client.status == 'blacklisted':
                        return JsonResponse({
                            'status': 'error', 
                            'message': f'Cannot create loan application for blacklisted client: {client.get_full_name()}'
                        }, status=403)
                    
                    if client.status == 'suspended':
                        return JsonResponse({
                            'status': 'error', 
                            'message': f'Cannot create loan application for suspended client: {client.get_full_name()}'
                        }, status=403)
                    
                    if client.status == 'inactive':
                        return JsonResponse({
                            'status': 'error', 
                            'message': f'Cannot create loan application for inactive client: {client.get_full_name()}'
                        }, status=403)
                
                # Validate amount, duration, and repayment method
                try:
                    loan_product.validate_amount(requested_amount)
                except ValueError as e:
                    return JsonResponse({'status': 'error', 'message': str(e)}, status=400)

                try:
                    loan_product.validate_duration(requested_duration)
                except ValueError as e:
                    return JsonResponse({'status': 'error', 'message': str(e)}, status=400)

                try:
                    loan_product.validate_repayment_method(repayment_method)
                except ValueError as e:
                    return JsonResponse({'status': 'error', 'message': str(e)}, status=400)
                
                # Calculate amounts
                # Convert days to months - use exact calculation, not ceiling
                # This ensures accurate interest: 90 days = 3 months, 60 days = 2 months, etc.
                months = Decimal(str(requested_duration)) / Decimal('30')
                months = max(Decimal('1'), months)  # Minimum 1 month
                interest_amount = loan_product.calculate_interest(requested_amount, months)
                processing_fee_amount = loan_product.calculate_processing_fee(requested_amount, months)
                total_amount = requested_amount + interest_amount + processing_fee_amount
                
                # Create loan application
                application = LoanApplication.objects.create(
                    borrower=client,
                    loan_product=loan_product,
                    requested_amount=requested_amount,
                    requested_duration=requested_duration,
                    purpose=purpose,
                    repayment_method=repayment_method,
                    interest_amount=interest_amount,
                    processing_fee_amount=processing_fee_amount,
                    total_amount=total_amount
                )
                
                print(f"DEBUG: Created application {application.application_number} for {client.get_full_name()}")
                
                # Auto-calculate credit score and handle auto-approval
                try:
                    # Try to get existing credit score
                    existing_score = LoanScoring.objects.filter(user=client).first()
                    if existing_score:
                        application.credit_score = existing_score.total_score
                    else:
                        application.credit_score = 0
                    
                    # Auto-approve if conditions are met
                    auto_approval_enabled = SystemSetting.get_bool('auto_approval_enabled', True)
                    auto_approval_min_score = SystemSetting.get_int('auto_approval_min_score', 80)
                    auto_approval_max_amount = Decimal(str(SystemSetting.get_float('auto_approval_max_amount', 25000)))
                    
                    if (auto_approval_enabled and 
                        application.credit_score >= auto_approval_min_score and 
                        requested_amount <= auto_approval_max_amount):
                        
                        application.auto_approved = True
                        application.status = 'approved'
                        application.reviewed_by = None
                        application.reviewed_at = datetime.now()
                        application.approval_notes = 'Auto-approved based on credit score'
                        
                        # Create loan record
                        loan = Loan.objects.create(
                            application=application,
                            borrower=client,
                            principal_amount=requested_amount,
                            interest_amount=interest_amount,
                            processing_fee=processing_fee_amount,
                            total_amount=total_amount,
                            disbursement_date=disbursement_date,
                            due_date=disbursement_date + timedelta(days=requested_duration),
                            duration_days=requested_duration,
                            status='active'
                        )
                        
                        messages.success(request, f'{loan_product.name} loan has been recorded and auto-approved!')
                    else:
                        messages.success(request, f'{loan_product.name} loan has been recorded and is under review.')
                        
                except Exception as e:
                    print(f"DEBUG: Credit score error: {e}")
                    messages.success(request, f'{loan_product.name} loan has been recorded and is under review.')
                
                application.save()
                
                # Create audit log
                AuditLog.objects.create(
                    user=request.user,
                    action='create',
                    model_name='LoanApplication',
                    object_id=str(application.id),
                    description=f'Added {loan_product.name} loan for {client.get_full_name()}'
                )
                
                # Create notification for admins
                if not application.auto_approved and SystemSetting.get_bool('email_notifications_enabled', True):
                    Notification.objects.create(
                        title=f'New {loan_product.name} Loan Application',
                        message=f'A new {loan_product.name} loan application has been submitted by {client.get_full_name()}',
                        priority='medium'
                    )
                
                return JsonResponse({
                    'status': 'success', 
                    'message': 'Loan application submitted successfully',
                    'application_id': str(application.id),
                    'application_number': application.application_number
                })
                
            except Exception as e:
                import traceback
                print("Error in loan application:", str(e))
                print(traceback.format_exc())
                return JsonResponse({
                    'status': 'error',
                    'message': f'An error occurred while processing your application: {str(e)}'
                }, status=500)
        
        # GET request - show the form
        # Get all active borrowers with proper status filtering
        clients = CustomUser.objects.filter(
            role='borrower'
        ).exclude(
            status__in=['deleted', 'archived']  # Exclude deleted/archived but allow inactive for admin review
        ).select_related().order_by('first_name', 'last_name')
        
        # Convert clients to a safe format for JavaScript
        clients_data = []
        for c in clients:
            client_data = {
                'id': str(c.id),
                'full_name': c.get_full_name(),
                'first_name': c.first_name or '',
                'last_name': c.last_name or '',
                'email': c.email or 'No email',
                'phone_number': str(c.phone_number) if c.phone_number else 'No phone',
                'business_name': getattr(c, 'business_name', '') or '',
                'id_number': getattr(c, 'id_number', '') or '',
                'status': getattr(c, 'status', 'active')
            }
            clients_data.append(client_data)
        
        # Convert loan products to dict with current settings
        loan_products_data = []
        for product in loan_products:
            try:
                product_data = product.to_dict()
                loan_products_data.append(product_data)
            except Exception as e:
                print(f"Error converting product {product.name}: {e}")
                # Fallback data
                loan_products_data.append({
                    'id': str(product.id),
                    'name': product.name,
                    'product_type': product.product_type,
                    'description': product.description,
                    'min_amount': float(product.min_amount),
                    'max_amount': float(product.max_amount),
                    'interest_rate': float(product.interest_rate),
                    'processing_fee': float(product.processing_fee),
                    'late_payment_penalty': float(product.late_payment_penalty),
                    'duration_months': product.duration_months,
                    'min_duration': product.min_duration,
                    'max_duration': product.max_duration,
                    'available_repayment_methods': product.available_repayment_methods or ['monthly'],
                    'requires_guarantor': product.requires_guarantor,
                    'requires_collateral': product.requires_collateral,
                    'is_active': product.is_active
                })
        
        context = {
            'loan_products': loan_products,
            'loan_products_json': json.dumps(loan_products_data, cls=DjangoJSONEncoder),
            'clients': clients,
            'clients_json': json.dumps(clients_data, cls=DjangoJSONEncoder),
            'selected_client': client,
            'today': datetime.now().date()
        }
        return render(request, 'loans/new_application.html', context)
        
    except Exception as e:
        import traceback
        print("Error in loan application view:", str(e))
        print(traceback.format_exc())
        messages.error(request, f'An error occurred: {str(e)}')
        return redirect('loans:loans')
