package com.xvji.admin;

import com.xvji.domain.Component;
import com.xvji.domain.PredictTask;
import com.xvji.quartz.domain.SysJob;
import com.xvji.quartz.service.ISysJobService;
import com.xvji.service.ComponentService;
import com.xvji.service.PredictTaskService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
@RunWith(SpringRunner.class)
public class PredictTaskServiceTest {

    @Autowired
    private PredictTaskService predictTaskService;

    @Autowired
    private ComponentService componentService; // 如需测试组件关联

    @Autowired
    private ISysJobService sysJobService;

    private static final Logger log = LoggerFactory.getLogger(PredictTaskServiceTest.class);


    // 测试用例：预测任务ID（提前在数据库准备或通过测试新增）
    private static final Long TEST_TASK_ID = 6005L;
    // 临时Cron：10秒后触发（便于测试，避免长时间等待）
    private static final String TEMP_CRON = "0/10 * * * * ?"; // 每10秒执行一次

    /**
     * 测试查询预测任务
     */
    @Test
    public void testQueryPredictTask() {
        // 1. 查询所有任务
        List<PredictTask> allTasks = predictTaskService.getAllPredictTasks();
        assertFalse(allTasks.isEmpty(), "预测任务列表不应为空");

        // 2. 查找目标任务
        PredictTask targetTask = allTasks.stream()
                .filter(task -> TEST_TASK_ID.equals(task.getPTaskId()))
                .findFirst()
                .orElse(null);
        
        assertNotNull(targetTask, "ID=" + TEST_TASK_ID + "的预测任务应存在");
        System.out.println("查询到目标任务：" + targetTask.getPTaskName());
    }

    /**
     * 测试编辑预测任务并同步到定时任务
     */
    @Test
    public void testUpdateAndSyncPredictTask() {
        // 1. 构建更新对象
        PredictTask updateTask = new PredictTask();
        updateTask.setPTaskId(TEST_TASK_ID);
        updateTask.setPTaskName("测试编辑-更新后名称"); // 新名称
        updateTask.setPCronExpression("0 15 3 * * ?");  // 新Cron（每天3:15执行）
        //updateTask.setPTaskStatus(0);                   // 状态改为停用

        // 2. 执行更新
        boolean updateResult = predictTaskService.updatePredictTask(updateTask);
        assertTrue(updateResult, "预测任务更新应成功");

        // 3. 验证业务表更新结果
        PredictTask updatedTask = predictTaskService.getById(TEST_TASK_ID);
        assertEquals("测试编辑-更新后名称", updatedTask.getPTaskName(), "任务名称未同步");
        assertEquals("0 15 3 * * ?", updatedTask.getPCronExpression(), "Cron表达式未同步");
        assertEquals(0, updatedTask.getPTaskStatus(), "任务状态未同步");
    }

    /**
     * 测试删除预测任务（级联删除组件和定时任务）
     */
    @Test
    public void testDeletePredictTask() {
        // 1. 执行删除
        boolean deleteResult = predictTaskService.deletePredictTaskWithComponents(TEST_TASK_ID);
        assertTrue(deleteResult, "预测任务删除应成功");

        // 2. 验证业务任务已删除
        PredictTask deletedTask = predictTaskService.getById(TEST_TASK_ID);
        assertNull(deletedTask, "预测任务未从业务表删除");

        // 3. 验证关联组件已删除（如需验证组件）
        /*
        List<Component> relatedComponents = componentService.list(
            new QueryWrapper<Component>()
                .eq("TASK_ID", TEST_TASK_ID)
                .eq("TASK_TYPE", 1)
        );
        assertTrue(relatedComponents.isEmpty(), "关联组件未级联删除");
        */
    }

    /**
     * 测试无效Cron表达式同步拦截
     */
    @Test
    public void testInvalidCronSync() {
        // 1. 构建含无效Cron的更新对象
        PredictTask invalidTask = new PredictTask();
        invalidTask.setPTaskId(TEST_TASK_ID);
        invalidTask.setPCronExpression("* * *"); // 无效Cron（缺少字段）

        // 2. 执行更新并验证异常
        assertThrows(RuntimeException.class, 
            () -> predictTaskService.updatePredictTask(invalidTask), 
            "无效Cron应抛出异常"
        );
    }

    /**
     * （可选）测试新增预测任务（如需完整覆盖）
     */
    @Test
    public void testAddPredictTask() {
        // 1. 构建新任务
        PredictTask newTask = new PredictTask();
        newTask.setPTaskName("测试新增任务");
        newTask.setPCronExpression("0 0 12 * * ?");
        //newTask.setPTaskStatus(1);

        // 2. 构建关联组件
        Component component = new Component();
        component.setComponentType("测试组件");
        component.setIsEnable(true);

        // 3. 执行新增
        boolean addResult = predictTaskService.addPredictTaskWithComponent(newTask, component);
        assertTrue(addResult, "新增预测任务应成功");
        assertNotNull(newTask.getPTaskId(), "新增任务应自动生成ID");
        System.out.println("新增任务ID：" + newTask.getPTaskId());
    }

    /**
     * 测试流程：
     * 1. 配置定时任务为10秒触发一次（临时Cron）
     * 2. 等待定时任务触发并调用目标接口
     * 3. 通过日志和执行结果验证接口是否被正确调用
     */
    @Test
    public void testCronTriggerInterface() throws InterruptedException, SchedulerException {
        // 1. 查找ID=6005关联的定时任务
        String conditionValue = "com.xvji.quartz.TaskQuartzJob.executePredictTask(" + TEST_TASK_ID + ")";
        SysJob targetJob = sysJobService.getSysJobByCondition(conditionValue);
        assertNotNull(targetJob, "未找到ID=" + TEST_TASK_ID + "关联的定时任务");

        // 2. 保存定时任务原有配置（测试后恢复，避免影响真实数据）
        String originalCron = targetJob.getCronExpression();
        String originalStatus = targetJob.getStatus();

        try {
            // 3. 修改定时任务为10秒触发一次，并启用
            targetJob.setCronExpression(TEMP_CRON);
            targetJob.setStatus("1"); // 启用任务
            boolean updateResult = sysJobService.updateSysJob(targetJob);
            assertTrue(updateResult, "修改定时任务Cron失败");
            log.info("已将定时任务[ID:{}]修改为每10秒触发一次，等待执行...", targetJob.getJobId());

            // 4. 等待30秒（确保至少触发2次）
            TimeUnit.SECONDS.sleep(30);

            // 5. 验证结果（通过日志或执行记录，以下为示例逻辑）
            // 5.1 检查目标接口是否被调用（需结合业务日志或执行记录表）
            log.info("请查看业务日志，确认是否输出 'executePredictTask(6005) 执行成功' 等类似记录");

            // 5.2 （可选）如果接口有执行结果存储，可直接查询验证
            /*
            ExecutionRecord record = executionRecordService.getLastRecord(TEST_TASK_ID);
            assertNotNull(record, "未找到接口执行记录");
            assertEquals("SUCCESS", record.getStatus(), "接口执行失败");
            */

        } finally {
            // 6. 恢复定时任务原有配置（关键：避免测试污染数据）
            targetJob.setCronExpression(originalCron);
            targetJob.setStatus(originalStatus);
            sysJobService.updateSysJob(targetJob);
            log.info("已恢复定时任务[ID:{}]原有配置：Cron={}, 状态={}",
                    targetJob.getJobId(), originalCron, originalStatus);
        }
    }
}
