"""
Test to verify the rollover loan total amount calculation fix.

This test ensures that the rollover_fee is not double-counted in the total_amount.
"""

from decimal import Decimal
from datetime import timedelta
from django.utils import timezone
from django.contrib.auth import get_user_model
from loans.models import LoanProduct, LoanApplication, Loan, RolloverRequest
import sys

User = get_user_model()


def test_rollover_total_amount_fix():
    """Test that rollover_fee is not double-counted in total_amount"""
    
    print("\n" + "="*70)
    print("TESTING ROLLOVER TOTAL AMOUNT CALCULATION FIX")
    print("="*70)
    
    # 1. Create test borrower
    print("\n1. Creating test borrower...")
    borrower = User.objects.create(
        username=f'test_rollover_borrower_{timezone.now().timestamp()}',
        email='test_rollover@example.com',
        role='borrower',
        first_name='Test',
        last_name='Rollover',
        phone_number='0712345678',
        id_number='12345678'
    )
    print(f"   ✓ Created borrower: {borrower.get_full_name()}")
    
    # 2. Create loan product
    print("\n2. Creating loan product...")
    loan_product, created = LoanProduct.objects.get_or_create(
        name='Test Boost',
        defaults={
            'product_type': 'boost',
            'interest_rate': 20.0,  # 20%
            'processing_fee': 2.0,   # 2%
            'min_amount': 1000,
            'max_amount': 50000,
            'min_duration': 30,
            'max_duration': 90,
            'rollover_fee_percentage': 10.0,  # 10% rollover fee
        }
    )
    print(f"   ✓ Using loan product: {loan_product.name}")
    
    # 3. Create original loan
    print("\n3. Creating original loan...")
    principal = Decimal('10000.00')
    interest = Decimal('2000.00')  # 20% of 10,000
    processing_fee = Decimal('200.00')  # 2% of 10,000
    
    application = LoanApplication.objects.create(
        borrower=borrower,
        loan_product=loan_product,
        requested_amount=principal,
        requested_duration=30,
        purpose='Test loan for rollover',
        repayment_method='monthly',
        interest_amount=interest,
        processing_fee_amount=processing_fee,
        total_amount=principal + interest + processing_fee,
        status='approved'
    )
    
    loan = Loan.objects.create(
        application=application,
        borrower=borrower,
        principal_amount=principal,
        interest_amount=interest,
        processing_fee=processing_fee,
        total_amount=principal + interest + processing_fee,
        disbursement_date=timezone.now(),
        due_date=timezone.now() + timedelta(days=30),
        duration_days=30,
        status='active'
    )
    
    original_total = loan.total_amount
    print(f"   ✓ Created loan: {loan.loan_number}")
    print(f"     - Principal: KES {principal:,.2f}")
    print(f"     - Interest: KES {interest:,.2f}")
    print(f"     - Processing Fee: KES {processing_fee:,.2f}")
    print(f"     - Total Amount: KES {original_total:,.2f}")
    
    # 4. Create rollover request
    print("\n4. Creating rollover request...")
    rollover_fee = Decimal('1000.00')  # 10% of 10,000
    
    rollover_request = RolloverRequest.objects.create(
        loan=loan,
        borrower=borrower,
        requested_amount=principal,  # Rolling over same amount
        requested_duration=30,
        reason='Testing rollover calculation',
        rollover_fee=rollover_fee,
        status='pending'
    )
    print(f"   ✓ Created rollover request with fee: KES {rollover_fee:,.2f}")
    
    # 5. Approve rollover
    print("\n5. Approving rollover...")
    admin_user = User.objects.filter(role='admin').first()
    if not admin_user:
        admin_user = User.objects.create(
            username='admin_test',
            email='admin@test.com',
            role='admin',
            first_name='Admin',
            last_name='User'
        )
    
    new_loan = rollover_request.approve(
        approved_by=admin_user,
        notes='Test rollover approval'
    )
    
    print(f"   ✓ Rollover approved, new loan created: {new_loan.loan_number}")
    
    # 6. Verify the calculations
    print("\n6. VERIFICATION:")
    print("-" * 70)
    
    new_principal = new_loan.principal_amount
    new_interest = new_loan.interest_amount
    new_processing_fee = new_loan.processing_fee
    new_total = new_loan.total_amount
    
    print(f"   New Loan Components:")
    print(f"     - Principal Amount:   KES {new_principal:,.2f}")
    print(f"     - Interest Amount:    KES {new_interest:,.2f}")
    print(f"     - Processing Fee:     KES {new_processing_fee:,.2f}")
    print(f"       (includes rollover fee of KES {rollover_fee:,.2f})")
    print(f"     - Total Amount:       KES {new_total:,.2f}")
    
    # Calculate expected values
    expected_processing_fee = processing_fee + rollover_fee  # 200 + 1000 = 1200
    expected_total = new_principal + new_interest + new_processing_fee
    
    # Note: processing_fee should already include rollover_fee, so we don't add it again
    expected_total_correct = new_principal + new_interest + expected_processing_fee
    
    print(f"\n   Expected Calculations:")
    print(f"     - Expected Processing Fee: KES {expected_processing_fee:,.2f}")
    print(f"       (processing_fee {processing_fee} + rollover_fee {rollover_fee})")
    print(f"     - Expected Total: KES {expected_total_correct:,.2f}")
    print(f"       (principal {new_principal} + interest {new_interest} + processing_fee {expected_processing_fee})")
    
    # Verify processing fee includes rollover fee
    print(f"\n   Checks:")
    processing_fee_check = new_processing_fee == expected_processing_fee
    print(f"     ✓ Processing fee includes rollover fee: {processing_fee_check}")
    if not processing_fee_check:
        print(f"       ERROR: Expected {expected_processing_fee}, got {new_processing_fee}")
    
    # Verify total amount is correct (NOT double-counting rollover_fee)
    total_check = new_total == expected_total_correct
    print(f"     ✓ Total amount is correct (no double-counting): {total_check}")
    if not total_check:
        print(f"       ERROR: Expected {expected_total_correct}, got {new_total}")
        print(f"       Difference: {new_total - expected_total_correct}")
    
    # Additional check: Ensure total_amount equals sum of components
    component_sum = new_principal + new_interest + new_processing_fee
    component_check = new_total == component_sum
    print(f"     ✓ Total equals sum of components: {component_check}")
    if not component_check:
        print(f"       ERROR: Expected {component_sum}, got {new_total}")
    
    # Final verdict
    print("\n" + "="*70)
    if processing_fee_check and total_check and component_check:
        print("✓ TEST PASSED: Rollover fee is not double-counted!")
        print("="*70)
        return True
    else:
        print("✗ TEST FAILED: Rollover calculation is incorrect!")
        print("="*70)
        return False
    
    # Cleanup
    new_loan.delete()
    loan.delete()
    application.delete()
    rollover_request.delete()
    borrower.delete()


if __name__ == '__main__':
    try:
        result = test_rollover_total_amount_fix()
        sys.exit(0 if result else 1)
    except Exception as e:
        print(f"\n✗ TEST ERROR: {str(e)}")
        import traceback
        traceback.print_exc()
        sys.exit(1)
