"""
Unit Tests for Date Filtering

Feature: comprehensive-reports-and-fixes
Tests date filtering accuracy in loans due reports.

Requirements: 8.6
"""

from django.test import TestCase
from datetime import date, datetime, timedelta
from decimal import Decimal
from django.utils import timezone
from loans.models import Loan, LoanApplication, LoanProduct
from users.models import CustomUser, Branch
from reports.comprehensive_reports import ComprehensiveReportsService


class TestDateFilteringUnit(TestCase):
    """Unit tests for date filtering in reports"""
    
    def setUp(self):
        """Set up test data"""
        # Create test branch
        self.branch = Branch.objects.create(
            name='Test Branch',
            code='TB001',
            is_main_branch=True
        )
        
        # Create test user (borrower)
        self.borrower = CustomUser.objects.create_user(
            username='testborrower',
            email='borrower@test.com',
            password='testpass123',
            first_name='Test',
            last_name='Borrower',
            phone_number='0712345678',
            branch=self.branch
        )
        
        # Create loan product
        self.loan_product = LoanProduct.objects.create(
            name='Test Product',
            product_type='boost',
            description='Test product for date filtering tests',
            min_amount=Decimal('1000.00'),
            max_amount=Decimal('100000.00'),
            interest_rate=Decimal('10.00'),
            processing_fee=Decimal('5.00'),
            min_duration=7,
            max_duration=90
        )
        
        self.reports_service = ComprehensiveReportsService()
        self.today = timezone.now().date()
    
    def test_today_only_filter_accuracy(self):
        """
        Test that today_only filter returns only loans due today.
        
        Validates: Requirement 8.6
        """
        # Create loans with different due dates
        # Loan due today
        app_today = LoanApplication.objects.create(
            borrower=self.borrower,
            loan_product=self.loan_product,
            requested_amount=Decimal('10000.00'),
            requested_duration=30,
            status='approved'
        )
        loan_today = Loan.objects.create(
            loan_number='LOAN-TODAY',
            application=app_today,
            borrower=self.borrower,
            principal_amount=Decimal('10000.00'),
            interest_amount=Decimal('1000.00'),
            processing_fee=Decimal('500.00'),
            total_amount=Decimal('11500.00'),
            disbursement_date=self.today - timedelta(days=7),
            due_date=datetime.combine(self.today, datetime.min.time()),
            duration_days=30,
            status='active',
            is_deleted=False,
            is_rolled_over=False
        )
        
        # Loan due tomorrow
        app_tomorrow = LoanApplication.objects.create(
            borrower=self.borrower,
            loan_product=self.loan_product,
            requested_amount=Decimal('10000.00'),
            requested_duration=30,
            status='approved'
        )
        loan_tomorrow = Loan.objects.create(
            loan_number='LOAN-TOMORROW',
            application=app_tomorrow,
            borrower=self.borrower,
            principal_amount=Decimal('10000.00'),
            interest_amount=Decimal('1000.00'),
            processing_fee=Decimal('500.00'),
            total_amount=Decimal('11500.00'),
            disbursement_date=self.today - timedelta(days=6),
            due_date=datetime.combine(self.today + timedelta(days=1), datetime.min.time()),
            duration_days=30,
            status='active',
            is_deleted=False,
            is_rolled_over=False
        )
        
        # Get loans due today only
        report_data = self.reports_service.get_loans_due_report(today_only=True)
        
        # Assert only today's loan is returned
        self.assertEqual(len(report_data['loans']), 1)
        self.assertEqual(report_data['loans'][0]['loan_number'], 'LOAN-TODAY')
    
    def test_date_range_filtering_various_ranges(self):
        """
        Test date range filtering with various ranges.
        
        Validates: Requirement 8.6
        """
        # Create loans with different due dates
        for i in range(5):
            app = LoanApplication.objects.create(
                borrower=self.borrower,
                loan_product=self.loan_product,
                requested_amount=Decimal('10000.00'),
                requested_duration=30,
                status='approved'
            )
            Loan.objects.create(
                loan_number=f'LOAN-{i:03d}',
                application=app,
                borrower=self.borrower,
                principal_amount=Decimal('10000.00'),
                interest_amount=Decimal('1000.00'),
                processing_fee=Decimal('500.00'),
                total_amount=Decimal('11500.00'),
                disbursement_date=self.today,
                due_date=datetime.combine(self.today + timedelta(days=i), datetime.min.time()),
                duration_days=30,
                status='active',
                is_deleted=False,
                is_rolled_over=False
            )
        
        # Test range: today to today+2 (should return 3 loans)
        report_data = self.reports_service.get_loans_due_report(
            start_date=self.today,
            end_date=self.today + timedelta(days=2)
        )
        self.assertEqual(len(report_data['loans']), 3)
        
        # Test range: today+1 to today+3 (should return 3 loans)
        report_data = self.reports_service.get_loans_due_report(
            start_date=self.today + timedelta(days=1),
            end_date=self.today + timedelta(days=3)
        )
        self.assertEqual(len(report_data['loans']), 3)
        
        # Test range: today to today+4 (should return all 5 loans)
        report_data = self.reports_service.get_loans_due_report(
            start_date=self.today,
            end_date=self.today + timedelta(days=4)
        )
        self.assertEqual(len(report_data['loans']), 5)
    
    def test_date_filtering_with_datetime_fields(self):
        """
        Test that date filtering works correctly with datetime fields.
        
        Validates: Requirement 8.6
        """
        # Create loan with due_date at different time of day
        app = LoanApplication.objects.create(
            borrower=self.borrower,
            loan_product=self.loan_product,
            requested_amount=Decimal('10000.00'),
            requested_duration=30,
            status='approved'
        )
        
        # Set due_date to today at 2:30 PM
        due_datetime = datetime.combine(self.today, datetime.min.time().replace(hour=14, minute=30))
        loan = Loan.objects.create(
            loan_number='LOAN-DATETIME',
            application=app,
            borrower=self.borrower,
            principal_amount=Decimal('10000.00'),
            interest_amount=Decimal('1000.00'),
            processing_fee=Decimal('500.00'),
            total_amount=Decimal('11500.00'),
            disbursement_date=self.today - timedelta(days=7),
            due_date=timezone.make_aware(due_datetime),
            duration_days=30,
            status='active',
            is_deleted=False,
            is_rolled_over=False
        )
        
        # Filter for today - should include the loan regardless of time
        report_data = self.reports_service.get_loans_due_report(today_only=True)
        
        self.assertEqual(len(report_data['loans']), 1)
        self.assertEqual(report_data['loans'][0]['loan_number'], 'LOAN-DATETIME')
    
    def test_empty_results_message(self):
        """
        Test that empty results are handled correctly.
        
        Validates: Requirement 8.6
        """
        # Don't create any loans
        
        # Get loans due today
        report_data = self.reports_service.get_loans_due_report(today_only=True)
        
        # Assert no loans returned
        self.assertEqual(len(report_data['loans']), 0)
        self.assertEqual(report_data['summary']['total_loans_due'], 0)
        self.assertEqual(report_data['summary']['total_amount_due'], Decimal('0.00'))
