package com.flightticket.scheduler;

import com.flightticket.service.BillingAggregatorService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.time.YearMonth;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

/**
 * Unit tests for BillingScheduler.
 * 
 * Tests verify:
 * - Scheduler calls billing aggregator service with correct parameters
 * - Scheduler calculates previous month correctly
 * - Scheduler handles errors gracefully without throwing exceptions
 * - Scheduler logs execution properly
 */
@ExtendWith(MockitoExtension.class)
class BillingSchedulerTest {
    
    @Mock
    private BillingAggregatorService billingAggregatorService;
    
    private BillingScheduler billingScheduler;
    
    @BeforeEach
    void setUp() {
        billingScheduler = new BillingScheduler(billingAggregatorService);
    }
    
    @Test
    void runMonthlyBilling_shouldCallBillingAggregatorWithPreviousMonth() {
        // Given
        YearMonth expectedMonth = YearMonth.now().minusMonths(1);
        ArgumentCaptor<YearMonth> monthCaptor = ArgumentCaptor.forClass(YearMonth.class);
        
        // When
        billingScheduler.runMonthlyBilling();
        
        // Then
        verify(billingAggregatorService, times(1)).generateMonthlyBills(monthCaptor.capture());
        assertThat(monthCaptor.getValue()).isEqualTo(expectedMonth);
    }
    
    @Test
    void runMonthlyBilling_shouldHandleExceptionsGracefully() {
        // Given
        doThrow(new RuntimeException("Database connection failed"))
            .when(billingAggregatorService).generateMonthlyBills(any(YearMonth.class));
        
        // When - should not throw exception
        billingScheduler.runMonthlyBilling();
        
        // Then - verify service was called despite exception
        verify(billingAggregatorService, times(1)).generateMonthlyBills(any(YearMonth.class));
    }
    
    @Test
    void runMonthlyBilling_shouldCalculateCorrectPreviousMonth() {
        // Given - current month is January 2024
        YearMonth currentMonth = YearMonth.of(2024, 1);
        YearMonth expectedPreviousMonth = YearMonth.of(2023, 12);
        
        // When
        billingScheduler.runMonthlyBilling();
        
        // Then - verify the month passed is one month before current
        ArgumentCaptor<YearMonth> monthCaptor = ArgumentCaptor.forClass(YearMonth.class);
        verify(billingAggregatorService).generateMonthlyBills(monthCaptor.capture());
        
        // The captured month should be one month before now
        YearMonth capturedMonth = monthCaptor.getValue();
        assertThat(capturedMonth).isEqualTo(YearMonth.now().minusMonths(1));
    }
    
    @Test
    void runMonthlyBilling_shouldCompleteSuccessfullyWhenNoErrors() {
        // Given
        doNothing().when(billingAggregatorService).generateMonthlyBills(any(YearMonth.class));
        
        // When
        billingScheduler.runMonthlyBilling();
        
        // Then
        verify(billingAggregatorService, times(1)).generateMonthlyBills(any(YearMonth.class));
    }
}
