"""
Simple test script for Property 4 and 5 without full Django test setup
"""
import os
import django

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'branch_system.settings')
django.setup()

from django.utils import timezone
from datetime import timedelta
from decimal import Decimal
import uuid

from loans.models import Loan, LoanProduct, LoanApplication
from users.models import CustomUser
from reports.filter_service import ReportFilterService


def test_property_4_rolled_over_exclusion():
    """Test that rolled-over loans are excluded from active reports"""
    print("\n=== Testing Property 4: Rolled-over loan exclusion ===")
    
    # Create test user
    try:
        user = CustomUser.objects.get(username='testuser_prop4')
    except CustomUser.DoesNotExist:
        user = CustomUser.objects.create_user(
            username='testuser_prop4',
            email='test_prop4@example.com',
            phone_number='+254700000020',
            first_name='Test',
            last_name='User'
        )
    
    # Create test product
    try:
        product = LoanProduct.objects.get(name='Test Product Prop4')
    except LoanProduct.DoesNotExist:
        product = LoanProduct.objects.create(
            name='Test Product Prop4',
            product_type='boost',
            description='Test product',
            min_amount=Decimal('1000'),
            max_amount=Decimal('50000'),
            interest_rate=Decimal('10.0'),
            processing_fee=Decimal('5.0'),
            min_duration=7,
            max_duration=90,
            available_repayment_methods=['monthly']
        )
    
    # Clean up any existing test loans
    try:
        Loan.objects.filter(loan_number__startswith='LOAN-PROP4').delete()
        LoanApplication.objects.filter(application_number__startswith='APP-PROP4').delete()
    except Exception:
        pass  # Ignore cleanup errors
    
    # Create 3 active loans
    active_loans = []
    for i in range(3):
        app = LoanApplication.objects.create(
            application_number=f'APP-P4A-{uuid.uuid4().hex[:6]}',
            borrower=user,
            loan_product=product,
            requested_amount=Decimal('10000'),
            requested_duration=30,
            purpose='Test',
            status='approved'
        )
        
        loan = Loan.objects.create(
            loan_number=f'LOAN-P4A-{uuid.uuid4().hex[:6]}',
            application=app,
            borrower=user,
            principal_amount=Decimal('10000'),
            interest_amount=Decimal('1000'),
            processing_fee=Decimal('500'),
            total_amount=Decimal('11500'),
            disbursement_date=timezone.now(),
            due_date=timezone.now() + timedelta(days=30),
            duration_days=30,
            status='active',
            is_rolled_over=False,
            is_deleted=False
        )
        active_loans.append(loan)
        print(f"  Created active loan: {loan.loan_number}")
    
    # Create 3 rolled-over loans
    rolled_over_loans = []
    for i in range(3):
        app = LoanApplication.objects.create(
            application_number=f'APP-P4R-{uuid.uuid4().hex[:6]}',
            borrower=user,
            loan_product=product,
            requested_amount=Decimal('10000'),
            requested_duration=30,
            purpose='Test',
            status='approved'
        )
        
        # Mix of status='rolled_over' and is_rolled_over=True
        if i % 2 == 0:
            status = 'rolled_over'
            is_rolled_over = True
        else:
            status = 'active'
            is_rolled_over = True
        
        loan = Loan.objects.create(
            loan_number=f'LOAN-P4R-{uuid.uuid4().hex[:6]}',
            application=app,
            borrower=user,
            principal_amount=Decimal('10000'),
            interest_amount=Decimal('1000'),
            processing_fee=Decimal('500'),
            total_amount=Decimal('11500'),
            disbursement_date=timezone.now(),
            due_date=timezone.now() + timedelta(days=30),
            duration_days=30,
            status=status,
            is_rolled_over=is_rolled_over,
            is_deleted=False
        )
        rolled_over_loans.append(loan)
        print(f"  Created rolled-over loan: {loan.loan_number} (status={status}, is_rolled_over={is_rolled_over})")
    
    # Apply filter to exclude rolled-over loans
    all_test_loan_ids = [loan.id for loan in active_loans + rolled_over_loans]
    queryset = Loan.objects.filter(id__in=all_test_loan_ids)
    filtered_queryset = ReportFilterService.apply_loan_status_filter(
        queryset, exclude_rolled_over=True, exclude_deleted=False
    )
    
    filtered_ids = set(filtered_queryset.values_list('id', flat=True))
    
    # Verify no rolled-over loans are in the results
    print("\n  Verifying rolled-over loans are excluded...")
    for loan in rolled_over_loans:
        if loan.id in filtered_ids:
            print(f"    ❌ FAIL: Rolled-over loan {loan.loan_number} was incorrectly included")
            return False
        else:
            print(f"    ✓ Rolled-over loan {loan.loan_number} correctly excluded")
    
    # Verify all active loans are in the results
    print("\n  Verifying active loans are included...")
    for loan in active_loans:
        if loan.id not in filtered_ids:
            print(f"    ❌ FAIL: Active loan {loan.loan_number} was incorrectly excluded")
            return False
        else:
            print(f"    ✓ Active loan {loan.loan_number} correctly included")
    
    # Verify the filtered queryset contains only active loans
    print("\n  Verifying filtered results...")
    for loan in filtered_queryset:
        if loan.status == 'rolled_over' or loan.is_rolled_over:
            print(f"    ❌ FAIL: Loan {loan.loan_number} has rolled_over status/flag but was included")
            return False
    
    print(f"\n  ✓ Property 4 test PASSED: {len(active_loans)} active loans included, {len(rolled_over_loans)} rolled-over loans excluded")
    
    # Cleanup (skip if there are database issues)
    try:
        for loan in active_loans + rolled_over_loans:
            loan.delete()
        LoanApplication.objects.filter(application_number__startswith='APP-PROP4').delete()
    except Exception as e:
        print(f"  Note: Cleanup skipped due to: {e}")
    
    return True


def test_property_5_soft_deleted_exclusion():
    """Test that soft-deleted loans are excluded from active reports"""
    print("\n=== Testing Property 5: Soft-deleted loan exclusion ===")
    
    # Create test user
    try:
        user = CustomUser.objects.get(username='testuser_prop5')
    except CustomUser.DoesNotExist:
        user = CustomUser.objects.create_user(
            username='testuser_prop5',
            email='test_prop5@example.com',
            phone_number='+254700000021',
            first_name='Test',
            last_name='User'
        )
    
    # Create test product
    try:
        product = LoanProduct.objects.get(name='Test Product Prop5')
    except LoanProduct.DoesNotExist:
        product = LoanProduct.objects.create(
            name='Test Product Prop5',
            product_type='boost',
            description='Test product',
            min_amount=Decimal('1000'),
            max_amount=Decimal('50000'),
            interest_rate=Decimal('10.0'),
            processing_fee=Decimal('5.0'),
            min_duration=7,
            max_duration=90,
            available_repayment_methods=['monthly']
        )
    
    # Clean up any existing test loans
    try:
        Loan.objects.filter(loan_number__startswith='LOAN-PROP5').delete()
        LoanApplication.objects.filter(application_number__startswith='APP-PROP5').delete()
    except Exception:
        pass  # Ignore cleanup errors
    
    # Create 3 active loans (not deleted)
    active_loans = []
    for i in range(3):
        app = LoanApplication.objects.create(
            application_number=f'APP-P5A-{uuid.uuid4().hex[:6]}',
            borrower=user,
            loan_product=product,
            requested_amount=Decimal('10000'),
            requested_duration=30,
            purpose='Test',
            status='approved'
        )
        
        loan = Loan.objects.create(
            loan_number=f'LOAN-P5A-{uuid.uuid4().hex[:6]}',
            application=app,
            borrower=user,
            principal_amount=Decimal('10000'),
            interest_amount=Decimal('1000'),
            processing_fee=Decimal('500'),
            total_amount=Decimal('11500'),
            disbursement_date=timezone.now(),
            due_date=timezone.now() + timedelta(days=30),
            duration_days=30,
            status='active',
            is_deleted=False,
            is_rolled_over=False
        )
        active_loans.append(loan)
        print(f"  Created active loan: {loan.loan_number}")
    
    # Create 3 soft-deleted loans
    deleted_loans = []
    for i in range(3):
        app = LoanApplication.objects.create(
            application_number=f'APP-P5D-{uuid.uuid4().hex[:6]}',
            borrower=user,
            loan_product=product,
            requested_amount=Decimal('10000'),
            requested_duration=30,
            purpose='Test',
            status='approved'
        )
        
        loan = Loan.objects.create(
            loan_number=f'LOAN-P5D-{uuid.uuid4().hex[:6]}',
            application=app,
            borrower=user,
            principal_amount=Decimal('10000'),
            interest_amount=Decimal('1000'),
            processing_fee=Decimal('500'),
            total_amount=Decimal('11500'),
            disbursement_date=timezone.now(),
            due_date=timezone.now() + timedelta(days=30),
            duration_days=30,
            status='active',
            is_deleted=True,
            deleted_at=timezone.now(),
            is_rolled_over=False
        )
        deleted_loans.append(loan)
        print(f"  Created deleted loan: {loan.loan_number} (is_deleted=True)")
    
    # Apply filter to exclude deleted loans
    all_test_loan_ids = [loan.id for loan in active_loans + deleted_loans]
    queryset = Loan.objects.filter(id__in=all_test_loan_ids)
    filtered_queryset = ReportFilterService.apply_loan_status_filter(
        queryset, exclude_rolled_over=False, exclude_deleted=True
    )
    
    filtered_ids = set(filtered_queryset.values_list('id', flat=True))
    
    # Verify no deleted loans are in the results
    print("\n  Verifying deleted loans are excluded...")
    for loan in deleted_loans:
        if loan.id in filtered_ids:
            print(f"    ❌ FAIL: Deleted loan {loan.loan_number} was incorrectly included")
            return False
        else:
            print(f"    ✓ Deleted loan {loan.loan_number} correctly excluded")
    
    # Verify all active loans are in the results
    print("\n  Verifying active loans are included...")
    for loan in active_loans:
        if loan.id not in filtered_ids:
            print(f"    ❌ FAIL: Active loan {loan.loan_number} was incorrectly excluded")
            return False
        else:
            print(f"    ✓ Active loan {loan.loan_number} correctly included")
    
    # Verify the filtered queryset contains only non-deleted loans
    print("\n  Verifying filtered results...")
    for loan in filtered_queryset:
        if loan.is_deleted:
            print(f"    ❌ FAIL: Loan {loan.loan_number} has is_deleted=True but was included")
            return False
    
    print(f"\n  ✓ Property 5 test PASSED: {len(active_loans)} active loans included, {len(deleted_loans)} deleted loans excluded")
    
    # Cleanup (skip if there are database issues)
    try:
        for loan in active_loans + deleted_loans:
            loan.delete()
        LoanApplication.objects.filter(application_number__startswith='APP-PROP5').delete()
    except Exception as e:
        print(f"  Note: Cleanup skipped due to: {e}")
    
    return True


if __name__ == '__main__':
    print("=" * 70)
    print("Running Property-Based Tests for Task 6.1 and 6.2")
    print("=" * 70)
    
    try:
        result_4 = test_property_4_rolled_over_exclusion()
        result_5 = test_property_5_soft_deleted_exclusion()
        
        print("\n" + "=" * 70)
        print("TEST SUMMARY")
        print("=" * 70)
        print(f"Property 4 (Rolled-over exclusion): {'PASSED ✓' if result_4 else 'FAILED ❌'}")
        print(f"Property 5 (Soft-deleted exclusion): {'PASSED ✓' if result_5 else 'FAILED ❌'}")
        print("=" * 70)
        
        if result_4 and result_5:
            print("\n✓ All property tests PASSED!")
            exit(0)
        else:
            print("\n❌ Some property tests FAILED!")
            exit(1)
            
    except Exception as e:
        print(f"\n❌ Error running tests: {e}")
        import traceback
        traceback.print_exc()
        exit(1)
