package com.example.demo.scheduler;

import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.example.demo.service.ImageToVideoService;
import com.example.demo.service.StoryboardVideoService;
import com.example.demo.service.TaskCleanupService;
import com.example.demo.service.TaskQueueService;
import com.example.demo.service.TextToVideoService;
import com.example.demo.service.UserService;
import com.example.demo.repository.UserMembershipRepository;

/**
 * 任务队列定时调度器
 * 每2分钟检查一次任务状态
 */
@Component
public class TaskQueueScheduler {

    private static final Logger logger = LoggerFactory.getLogger(TaskQueueScheduler.class);

    @Autowired
    private TaskQueueService taskQueueService;

    @Autowired
    private com.example.demo.repository.TaskStatusRepository taskStatusRepository;

    @Autowired
    private com.example.demo.service.TaskStatusPollingService taskStatusPollingService;

    @Autowired
    private TaskCleanupService taskCleanupService;
    
    @Autowired
    private StoryboardVideoService storyboardVideoService;
    
    @Autowired
    private TextToVideoService textToVideoService;
    
    @Autowired
    private ImageToVideoService imageToVideoService;
    
    @Autowired
    private UserService userService;
    
    @Autowired
    private UserMembershipRepository userMembershipRepository;

    /**
     * 处理待处理任务
     * 每2分钟执行一次，处理队列中的待处理任务
     */
    @Scheduled(fixedRate = 120000) // 2分钟 = 120000毫秒
    public void processPendingTasks() {
        try {
            int count = taskQueueService.processPendingTasks();
            if (count > 0) {
                logger.info("加载了 {} 个待处理任务到队列", count);
            }
        } catch (Exception e) {
            logger.error("处理待处理任务失败", e);
        }
    }

    /**
     * 检查任务状态 - 每2分钟执行一次轮询查询
     * 固定间隔：120000毫秒 = 2分钟
     * 查询正在处理的任务状态，更新完成/失败状态
     * 优化：只在有待处理任务时才执行轮询，节省资源
     */
    @Scheduled(fixedRate = 120000) // 2分钟 = 120000毫秒
    public void checkTaskStatuses() {
        try {
            // 新策略：仅在任务队列中存在待处理任务时才进行轮询查询
            boolean hasQueueTasks = taskQueueService.hasTasksToCheck();
            long processingStatusCount = taskStatusRepository.countByStatus(com.example.demo.model.TaskStatus.Status.PROCESSING);
            
            if (!hasQueueTasks && processingStatusCount == 0) {
                // 没有待处理任务，静默跳过轮询（不输出日志）
                return;
            }
            
            logger.debug("[轮询调度] TaskQueue待检查任务: {}, TaskStatus处理中任务: {}", 
                hasQueueTasks, processingStatusCount);

            // 队列中有任务：检查队列内任务状态
            if (hasQueueTasks) {
                logger.debug("[轮询调度] 开始检查TaskQueue任务状态");
                taskQueueService.checkTaskStatuses();
            }

            // TaskStatus表中有处理中任务：调用轮询服务
            if (processingStatusCount > 0) {
                logger.debug("[轮询调度] 开始轮询TaskStatus任务");
                taskStatusPollingService.pollTaskStatuses();
            }
        } catch (Exception e) {
            logger.error("检查任务状态失败", e);
        }
    }
    
    /**
     * 检查分镜视频超时任务
     * 每2分钟执行一次，分两个阶段检查：
     * 1. 分镜图生成阶段：10分钟超时
     * 2. 视频生成阶段：1小时超时
     */
    @Scheduled(fixedRate = 120000) // 2分钟 = 120000毫秒
    public void checkStoryboardImageGenerationTimeout() {
        try {
            int handledCount = storyboardVideoService.checkAndHandleTimeoutTasks();
            if (handledCount > 0) {
                logger.warn("处理了 {} 个超时的分镜视频任务", handledCount);
            }
        } catch (Exception e) {
            logger.error("检查分镜视频超时任务失败", e);
        }
    }
    
    /**
     * 检查文生视频超时任务
     * 每2分钟执行一次，超时时间：1小时
     */
    @Scheduled(fixedRate = 120000) // 2分钟 = 120000毫秒
    public void checkTextToVideoTimeout() {
        try {
            int handledCount = textToVideoService.checkAndHandleTimeoutTasks();
            if (handledCount > 0) {
                logger.warn("处理了 {} 个超时的文生视频任务", handledCount);
            }
        } catch (Exception e) {
            logger.error("检查文生视频超时任务失败", e);
        }
    }
    
    /**
     * 检查图生视频超时任务
     * 每2分钟执行一次，超时时间：1小时
     */
    @Scheduled(fixedRate = 120000) // 2分钟 = 120000毫秒
    public void checkImageToVideoTimeout() {
        try {
            int handledCount = imageToVideoService.checkAndHandleTimeoutTasks();
            if (handledCount > 0) {
                logger.warn("处理了 {} 个超时的图生视频任务", handledCount);
            }
        } catch (Exception e) {
            logger.error("检查图生视频超时任务失败", e);
        }
    }

    /**
     * 检查任务队列超时
     * 每2分钟执行一次，超时时间：1小时
     * 超过1小时仍在PENDING或PROCESSING状态的队列任务将被标记为失败
     */
    @Scheduled(fixedRate = 120000) // 2分钟 = 120000毫秒
    public void checkQueueTimeout() {
        try {
            int handledCount = taskQueueService.checkAndHandleQueueTimeoutTasks();
            if (handledCount > 0) {
                logger.warn("处理了 {} 个超时的队列任务", handledCount);
            }
        } catch (Exception e) {
            logger.error("检查队列超时任务失败", e);
        }
    }

    /**
     * 清理过期任务
     * 每天凌晨2点执行一次
     */
    @Scheduled(cron = "0 0 2 * * ?")
    public void cleanupExpiredTasks() {
        try {
            logger.info("开始清理过期任务");
            int cleanedCount = taskQueueService.cleanupExpiredTasks();
            logger.info("清理过期任务完成，清理数量: {}", cleanedCount);
        } catch (Exception e) {
            logger.error("清理过期任务失败", e);
        }
    }

    /**
     * 定期清理任务
     * 每天凌晨4点执行一次，清理已完成和失败的任务
     */
    @Scheduled(cron = "0 0 4 * * ?")
    public void performTaskCleanup() {
        try {
            logger.info("开始执行定期任务清理");
            Map<String, Object> result = taskCleanupService.performFullCleanup();
            logger.info("定期任务清理完成: {}", result);
        } catch (Exception e) {
            logger.error("定期任务清理失败", e);
        }
    }
    
    /**
     * 定期修复 UserWork 状态与业务任务表的不一致
     * 每 5 分钟执行一次，覆盖运行时因异常/超时导致的状态漏更新
     */
    @Scheduled(fixedRate = 300000) // 5分钟 = 300000毫秒
    public void repairUserWorkStatus() {
        try {
            taskQueueService.repairUserWorkStatus();
        } catch (Exception e) {
            logger.error("定期修复UserWork状态失败", e);
        }
    }

    /**
     * 处理过期会员
     * 每天凌晨1点执行一次，将过期会员状态改为EXPIRED，清零积分
     */
    @Scheduled(cron = "0 0 1 * * ?")
    public void processExpiredMemberships() {
        try {
            logger.info("开始处理过期会员");
            int processedCount = userService.processExpiredMemberships(userMembershipRepository);
            logger.info("处理过期会员完成，处理数量: {}", processedCount);
        } catch (Exception e) {
            logger.error("处理过期会员失败", e);
        }
    }

}