package com.flightticket.integration;

import com.flightticket.aspect.AmadeusUsageAspect;
import com.flightticket.repository.BillingRecordRepository;
import com.flightticket.repository.PricingConfigRepository;
import com.flightticket.repository.UsageLedgerRepository;
import com.flightticket.scheduler.BillingScheduler;
import com.flightticket.service.BillingAggregatorService;
import com.flightticket.service.PricingConfigService;
import com.flightticket.service.UsageLoggerService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.test.context.ActiveProfiles;

import java.util.concurrent.Executor;

import static org.assertj.core.api.Assertions.assertThat;

/**
 * Integration test to verify all billing system components are properly wired in Spring context.
 * 
 * This test validates:
 * - AOP aspect is registered and active
 * - Async executor is configured correctly
 * - Scheduler is enabled and registered
 * - All repositories are autowired correctly
 * - All services are autowired correctly
 * - Security context integration is available
 * 
 * Requirements: All (Task 14.1)
 */
@SpringBootTest
@ActiveProfiles("test")
class BillingSystemIntegrationTest {
    
    @Autowired
    private ApplicationContext applicationContext;
    
    @Autowired(required = false)
    private AmadeusUsageAspect amadeusUsageAspect;
    
    @Autowired(required = false)
    private UsageLoggerService usageLoggerService;
    
    @Autowired(required = false)
    private PricingConfigService pricingConfigService;
    
    @Autowired(required = false)
    private BillingAggregatorService billingAggregatorService;
    
    @Autowired(required = false)
    private BillingScheduler billingScheduler;
    
    @Autowired(required = false)
    private UsageLedgerRepository usageLedgerRepository;
    
    @Autowired(required = false)
    private PricingConfigRepository pricingConfigRepository;
    
    @Autowired(required = false)
    private BillingRecordRepository billingRecordRepository;
    
    @Test
    void contextLoads() {
        assertThat(applicationContext).isNotNull();
    }
    
    /**
     * Verify AOP aspect is registered in Spring context.
     * 
     * The AmadeusUsageAspect should be:
     * - Registered as a Spring bean
     * - Annotated with @Aspect and @Component
     * - Ready to intercept Amadeus API calls
     */
    @Test
    void verifyAopAspectIsRegistered() {
        assertThat(amadeusUsageAspect)
            .as("AmadeusUsageAspect should be registered in Spring context")
            .isNotNull();
        
        // Verify the aspect bean is actually an aspect
        assertThat(amadeusUsageAspect.getClass().isAnnotationPresent(org.aspectj.lang.annotation.Aspect.class))
            .as("AmadeusUsageAspect should be annotated with @Aspect")
            .isTrue();
        
        assertThat(amadeusUsageAspect.getClass().isAnnotationPresent(org.springframework.stereotype.Component.class))
            .as("AmadeusUsageAspect should be annotated with @Component")
            .isTrue();
    }
    
    /**
     * Verify async executor is configured correctly.
     * 
     * The async executor should be:
     * - Registered as a bean named "taskExecutor"
     * - Properly configured with thread pool settings
     * - Available for @Async method execution
     */
    @Test
    void verifyAsyncExecutorIsConfigured() {
        // Verify @EnableAsync is present on the application
        boolean asyncEnabled = applicationContext.getBeansWithAnnotation(EnableAsync.class).size() > 0;
        assertThat(asyncEnabled)
            .as("@EnableAsync should be present in the application context")
            .isTrue();
        
        // Verify taskExecutor bean exists
        assertThat(applicationContext.containsBean("taskExecutor"))
            .as("taskExecutor bean should be registered")
            .isTrue();
        
        // Verify taskExecutor is an Executor
        Executor taskExecutor = applicationContext.getBean("taskExecutor", Executor.class);
        assertThat(taskExecutor)
            .as("taskExecutor should be an instance of Executor")
            .isNotNull();
    }
    
    /**
     * Verify scheduler is enabled and registered.
     * 
     * The scheduler should be:
     * - Enabled via @EnableScheduling
     * - BillingScheduler bean registered
     * - Ready to execute scheduled billing jobs
     */
    @Test
    void verifySchedulerIsEnabledAndRegistered() {
        // Verify @EnableScheduling is present on the application
        boolean schedulingEnabled = applicationContext.getBeansWithAnnotation(EnableScheduling.class).size() > 0;
        assertThat(schedulingEnabled)
            .as("@EnableScheduling should be present in the application context")
            .isTrue();
        
        // Verify BillingScheduler bean exists
        assertThat(billingScheduler)
            .as("BillingScheduler should be registered in Spring context")
            .isNotNull();
        
        assertThat(billingScheduler.getClass().isAnnotationPresent(org.springframework.stereotype.Component.class))
            .as("BillingScheduler should be annotated with @Component")
            .isTrue();
    }
    
    /**
     * Verify all repositories are autowired correctly.
     * 
     * All billing-related repositories should be:
     * - Registered as Spring beans
     * - Properly autowired
     * - Ready for database operations
     */
    @Test
    void verifyAllRepositoriesAreAutowired() {
        assertThat(usageLedgerRepository)
            .as("UsageLedgerRepository should be autowired")
            .isNotNull();
        
        assertThat(pricingConfigRepository)
            .as("PricingConfigRepository should be autowired")
            .isNotNull();
        
        assertThat(billingRecordRepository)
            .as("BillingRecordRepository should be autowired")
            .isNotNull();
    }
    
    /**
     * Verify all services are autowired correctly.
     * 
     * All billing-related services should be:
     * - Registered as Spring beans
     * - Properly autowired with their dependencies
     * - Ready for business logic execution
     */
    @Test
    void verifyAllServicesAreAutowired() {
        assertThat(usageLoggerService)
            .as("UsageLoggerService should be autowired")
            .isNotNull();
        
        assertThat(pricingConfigService)
            .as("PricingConfigService should be autowired")
            .isNotNull();
        
        assertThat(billingAggregatorService)
            .as("BillingAggregatorService should be autowired")
            .isNotNull();
    }
    
    /**
     * Verify security context integration is available.
     * 
     * The security configuration should be:
     * - Properly configured for JWT authentication
     * - Ready to provide client ID from security context
     * - Available for the AOP aspect to extract client information
     */
    @Test
    void verifySecurityContextIntegrationIsAvailable() {
        // Verify SecurityConfig bean exists
        assertThat(applicationContext.containsBean("securityConfig"))
            .as("SecurityConfig should be registered")
            .isTrue();
        
        // Verify SecurityFilterChain bean exists
        assertThat(applicationContext.containsBean("securityFilterChain"))
            .as("SecurityFilterChain should be registered")
            .isTrue();
        
        // Verify JwtAuthenticationConverter bean exists
        assertThat(applicationContext.containsBean("jwtAuthenticationConverter"))
            .as("JwtAuthenticationConverter should be registered")
            .isTrue();
    }
    
    /**
     * Verify configuration properties are loaded correctly.
     * 
     * The billing configuration properties should be:
     * - Loaded from application.yml
     * - Available for injection into beans
     * - Properly configured with default values
     */
    @Test
    void verifyConfigurationPropertiesAreLoaded() {
        // Verify billing configuration properties exist in environment
        String corePoolSize = applicationContext.getEnvironment().getProperty("billing.async.core-pool-size");
        String maxPoolSize = applicationContext.getEnvironment().getProperty("billing.async.max-pool-size");
        String queueCapacity = applicationContext.getEnvironment().getProperty("billing.async.queue-capacity");
        String schedulerCron = applicationContext.getEnvironment().getProperty("billing.scheduler.cron");
        String schedulerEnabled = applicationContext.getEnvironment().getProperty("billing.scheduler.enabled");
        
        // These should either be set or have defaults
        assertThat(corePoolSize)
            .as("billing.async.core-pool-size should be configured or have default")
            .isNotNull();
        
        assertThat(maxPoolSize)
            .as("billing.async.max-pool-size should be configured or have default")
            .isNotNull();
        
        assertThat(queueCapacity)
            .as("billing.async.queue-capacity should be configured or have default")
            .isNotNull();
        
        assertThat(schedulerCron)
            .as("billing.scheduler.cron should be configured or have default")
            .isNotNull();
        
        assertThat(schedulerEnabled)
            .as("billing.scheduler.enabled should be configured or have default")
            .isNotNull();
    }
    
    /**
     * Verify all components are properly integrated.
     * 
     * This is a comprehensive check that all billing system components
     * are properly wired together and ready for operation.
     */
    @Test
    void verifyAllComponentsAreProperlyIntegrated() {
        // Verify the complete chain of dependencies
        assertThat(amadeusUsageAspect).isNotNull();
        assertThat(usageLoggerService).isNotNull();
        assertThat(pricingConfigService).isNotNull();
        assertThat(billingAggregatorService).isNotNull();
        assertThat(billingScheduler).isNotNull();
        
        assertThat(usageLedgerRepository).isNotNull();
        assertThat(pricingConfigRepository).isNotNull();
        assertThat(billingRecordRepository).isNotNull();
        
        // Verify async and scheduling are enabled
        boolean asyncEnabled = applicationContext.getBeansWithAnnotation(EnableAsync.class).size() > 0;
        boolean schedulingEnabled = applicationContext.getBeansWithAnnotation(EnableScheduling.class).size() > 0;
        
        assertThat(asyncEnabled).isTrue();
        assertThat(schedulingEnabled).isTrue();
        
        // Verify security context is available
        assertThat(applicationContext.containsBean("securityFilterChain")).isTrue();
    }
}
