package com.rj.scheduler;

import com.rj.entity.CustomerManagementStatistics;
import com.rj.service.ICustomerManagementStatisticsService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;

import java.time.LocalDate;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

/**
 * CustomerStatisticsScheduler 集成测试
 * 测试客户统计调度器的执行和统计数据的生成
 * 
 * @author 李中华 ,spllzh
 * @since 2025-08-07
 */
@SpringBootTest
@ActiveProfiles("test")
@DisplayName("客户统计调度器集成测试")
class CustomerStatisticsSchedulerIntegrationTest {

    @Autowired
    private CustomerStatisticsScheduler customerStatisticsScheduler;

    @Autowired
    private ICustomerManagementStatisticsService customerStatisticsService;

    /**
     * 测试手动触发统计任务
     */
    @Test
    @DisplayName("测试手动触发统计任务")
    void testManualGenerateStatistics() {
        // 准备测试日期（使用昨天的日期）
        LocalDate testDate = LocalDate.now().minusDays(1);
        
        System.out.println("开始测试手动触发统计任务，统计日期: " + testDate);
        
        // 执行手动统计任务
        int count = customerStatisticsScheduler.manualGenerateStatistics(testDate);
        
        // 验证结果
        assertTrue(count >= 0, "统计记录数应该大于等于0");
        System.out.println("生成统计记录数: " + count);
        
        // 验证数据是否保存到数据库
        List<CustomerManagementStatistics> statistics = customerStatisticsService.getStatisticsByDateRange(testDate, testDate);
        assertNotNull(statistics, "统计列表不应该为null");
        // 验证统计记录的完整性
        if (!statistics.isEmpty()) {
            CustomerManagementStatistics firstStat = statistics.get(0);
            assertNotNull(firstStat.getId(), "统计记录ID不应为空");
            assertEquals(testDate, firstStat.getStatisticsDate(), "统计日期应该正确");
            assertNotNull(firstStat.getTenantId(), "租户ID不应为空");
            assertNotNull(firstStat.getDealershipId(), "经销商ID不应为空");
            assertNotNull(firstStat.getSalesId(), "销售ID不应为空");
            assertNotNull(firstStat.getCountByDealership(), "按经销商统计数量不应为空");
            assertNotNull(firstStat.getCountBySales(), "按销售统计数量不应为空");
            assertNotNull(firstStat.getCountByProject(), "按项目统计数量不应为空");
            
            System.out.println("统计记录详情:");
            System.out.println("  ID: " + firstStat.getId());
            System.out.println("  租户ID: " + firstStat.getTenantId());
            System.out.println("  经销商ID: " + firstStat.getDealershipId());
            System.out.println("  经销商名称: " + firstStat.getDealershipName());
            System.out.println("  销售ID: " + firstStat.getSalesId());
            System.out.println("  按经销商统计数量: " + firstStat.getCountByDealership());
            System.out.println("  按销售统计数量: " + firstStat.getCountBySales());
            System.out.println("  按项目统计数量: " + firstStat.getCountByProject());
            System.out.println("  统计日期: " + firstStat.getStatisticsDate());
        }
    }

    /**
     * 测试重复执行统计任务（应该先删除再生成）
     */
    @Test
    @DisplayName("测试重复执行统计任务")
    void testDuplicateStatisticsGeneration() {
        LocalDate testDate = LocalDate.now().minusDays(2);
        
        System.out.println("开始测试重复执行统计任务，统计日期: " + testDate);
        
        // 第一次执行
        int firstCount = customerStatisticsScheduler.manualGenerateStatistics(testDate);
        System.out.println("第一次执行生成记录数: " + firstCount);
        
        // 验证第一次执行的结果
        List<CustomerManagementStatistics> firstStatistics = customerStatisticsService.getStatisticsByDateRange(testDate, testDate);
        assertEquals(firstCount, firstStatistics.size(), "第一次执行后记录数应该正确");
        
        // 第二次执行（应该先删除再生成）
        int secondCount = customerStatisticsScheduler.manualGenerateStatistics(testDate);
        System.out.println("第二次执行生成记录数: " + secondCount);
        
        // 验证第二次执行的结果（记录数应该与第一次一致或接近）
        List<CustomerManagementStatistics> secondStatistics = customerStatisticsService.getStatisticsByDateRange(testDate, testDate);
        assertEquals(secondCount, secondStatistics.size(), "第二次执行后记录数应该正确");
        
        // 验证记录数应该一致（因为同一天的数据应该相同）
        assertEquals(firstCount, secondCount, "重复执行应该生成相同数量的记录");
    }

    /**
     * 测试查询指定日期范围的统计数据
     */
    @Test
    @DisplayName("测试查询指定日期范围的统计数据")
    void testGetStatisticsByDateRange() {
        LocalDate startDate = LocalDate.now().minusDays(7);
        LocalDate endDate = LocalDate.now().minusDays(1);
        
        System.out.println("开始测试查询日期范围统计，开始日期: " + startDate + ", 结束日期: " + endDate);
        
        // 查询统计数据
        List<CustomerManagementStatistics> statistics = customerStatisticsService.getStatisticsByDateRange(startDate, endDate);
        
        // 验证结果
        assertNotNull(statistics, "统计列表不应该为null");
        assertTrue(statistics.size() >= 0, "统计记录数应该大于等于0");
        
        System.out.println("查询到统计记录数: " + statistics.size());
        
        // 验证统计记录的日期范围
        for (CustomerManagementStatistics stat : statistics) {
            assertTrue(stat.getStatisticsDate().isAfter(startDate.minusDays(1)) || 
                      stat.getStatisticsDate().isEqual(startDate), 
                      "统计日期应该在开始日期之后或等于开始日期");
            assertTrue(stat.getStatisticsDate().isBefore(endDate.plusDays(1)) || 
                      stat.getStatisticsDate().isEqual(endDate), 
                      "统计日期应该在结束日期之前或等于结束日期");
        }
        
        // 打印部分统计信息
        if (!statistics.isEmpty()) {
            System.out.println("前5条统计记录:");
            statistics.stream().limit(5).forEach(stat -> {
                System.out.println("  日期: " + stat.getStatisticsDate() + 
                                 ", 经销商: " + stat.getDealershipName() + 
                                 ", 经销商统计: " + stat.getCountByDealership() + 
                                 ", 销售统计: " + stat.getCountBySales() + 
                                 ", 项目统计: " + stat.getCountByProject());
            });
        }
    }

    /**
     * 测试查询指定经销商的统计数据
     */
    @Test
    @DisplayName("测试查询指定经销商的统计数据")
    void testGetStatisticsByDealership() {
        LocalDate startDate = LocalDate.now().minusDays(7);
        LocalDate endDate = LocalDate.now().minusDays(1);
        
        // 先查询所有统计数据，获取一个经销商ID
        List<CustomerManagementStatistics> allStatistics = customerStatisticsService.getStatisticsByDateRange(startDate, endDate);
        
        if (allStatistics.isEmpty()) {
            System.out.println("没有统计数据，跳过经销商查询测试");
            return;
        }
        
        String dealershipId = allStatistics.get(0).getDealershipId();
        System.out.println("开始测试查询经销商统计，经销商ID: " + dealershipId);
        
        // 查询指定经销商的统计数据
        List<CustomerManagementStatistics> statistics = customerStatisticsService.getStatisticsByDealership(dealershipId, startDate, endDate);
        
        // 验证结果
        assertNotNull(statistics, "统计列表不应该为null");
        assertTrue(statistics.size() >= 0, "统计记录数应该大于等于0");
        
        System.out.println("查询到经销商统计记录数: " + statistics.size());
        
        // 验证所有记录都是指定经销商的
        for (CustomerManagementStatistics stat : statistics) {
            assertEquals(dealershipId, stat.getDealershipId(), "所有记录应该属于指定经销商");
        }
    }

    /**
     * 测试查询指定销售的统计数据
     */
    @Test
    @DisplayName("测试查询指定销售的统计数据")
    void testGetStatisticsBySales() {
        LocalDate startDate = LocalDate.now().minusDays(7);
        LocalDate endDate = LocalDate.now().minusDays(1);
        
        // 先查询所有统计数据，获取一个销售ID
        List<CustomerManagementStatistics> allStatistics = customerStatisticsService.getStatisticsByDateRange(startDate, endDate);
        
        if (allStatistics.isEmpty()) {
            System.out.println("没有统计数据，跳过销售查询测试");
            return;
        }
        
        String salesId = allStatistics.get(0).getSalesId();
        System.out.println("开始测试查询销售统计，销售ID: " + salesId);
        
        // 查询指定销售的统计数据
        List<CustomerManagementStatistics> statistics = customerStatisticsService.getStatisticsBySales(salesId, startDate, endDate);
        
        // 验证结果
        assertNotNull(statistics, "统计列表不应该为null");
        assertTrue(statistics.size() >= 0, "统计记录数应该大于等于0");
        
        System.out.println("查询到销售统计记录数: " + statistics.size());
        
        // 验证所有记录都是指定销售的
        for (CustomerManagementStatistics stat : statistics) {
            assertEquals(salesId, stat.getSalesId(), "所有记录应该属于指定销售");
        }
    }

    /**
     * 测试统计数据的完整性
     */
    @Test
    @DisplayName("测试统计数据的完整性")
    void testStatisticsDataIntegrity() {
        LocalDate testDate = LocalDate.now().minusDays(1);
        
        System.out.println("开始测试统计数据完整性，统计日期: " + testDate);
        
        // 执行统计任务
        int count = customerStatisticsScheduler.manualGenerateStatistics(testDate);
        
        if (count == 0) {
            System.out.println("没有生成统计数据，跳过完整性测试");
            return;
        }
        
        // 查询统计数据
        List<CustomerManagementStatistics> statistics = customerStatisticsService.getStatisticsByDateRange(testDate, testDate);
        
        // 验证每条记录的完整性
        for (CustomerManagementStatistics stat : statistics) {
            // 验证必填字段
            assertNotNull(stat.getId(), "ID不应为空");
            assertNotNull(stat.getStatisticsDate(), "统计日期不应为空");
            assertNotNull(stat.getTenantId(), "租户ID不应为空");
            assertNotNull(stat.getDealershipId(), "经销商ID不应为空");
            assertNotNull(stat.getSalesId(), "销售ID不应为空");
            
            // 验证统计数量字段
            assertNotNull(stat.getCountByDealership(), "按经销商统计数量不应为空");
            assertNotNull(stat.getCountBySales(), "按销售统计数量不应为空");
            assertNotNull(stat.getCountByProject(), "按项目统计数量不应为空");
            
            // 验证统计数量应该大于等于0
            assertTrue(stat.getCountByDealership() >= 0, "按经销商统计数量应该大于等于0");
            assertTrue(stat.getCountBySales() >= 0, "按销售统计数量应该大于等于0");
            assertTrue(stat.getCountByProject() >= 0, "按项目统计数量应该大于等于0");
            
            // 验证时间字段
            assertNotNull(stat.getCreatedAt(), "创建时间不应为空");
            assertNotNull(stat.getUpdatedAt(), "更新时间不应为空");
        }
        
        System.out.println("统计数据完整性验证通过，共验证 " + statistics.size() + " 条记录");
    }

    /**
     * 测试生成昨天的统计数据
     */
    @Test
    @DisplayName("测试生成昨天的统计数据")
    void testGenerateYesterdayStatistics() {
        System.out.println("开始测试生成昨天的统计数据");
        
        // 执行生成昨天的统计数据
        int count = customerStatisticsService.generateYesterdayStatistics();
        
        // 验证结果
        assertTrue(count >= 0, "统计记录数应该大于等于0");
        System.out.println("生成昨天统计记录数: " + count);
        
        // 验证数据是否保存
        LocalDate yesterday = LocalDate.now().minusDays(1);
        List<CustomerManagementStatistics> statistics = customerStatisticsService.getStatisticsByDateRange(yesterday, yesterday);
        assertEquals(count, statistics.size(), "生成的记录数应该与查询到的记录数一致");
    }
}

