package com.ruoyi.credit.scheduler;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

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

import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.credit.event.LoanChangeEvent;
import com.ruoyi.credit.service.ILoanConsistencyService;
import com.ruoyi.credit.service.ValidationQueueManager;

/**
 * 验证任务调度器
 * 添加批量验证的后台任务调度
 * 
 * @author ruoyi
 * @date 2025-12-31
 */
@Component
public class ValidationScheduler {

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

    @Autowired
    private ILoanConsistencyService loanConsistencyService;

    @Autowired
    private ValidationQueueManager validationQueueManager;

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    /** 是否启用定时验证 */
    @Value("${loan.validation.scheduler.enabled:true}")
    private boolean schedulerEnabled;

    /** 批量验证批次大小 */
    @Value("${loan.validation.scheduler.batchSize:100}")
    private int batchSize;

    /** 重新验证时间阈值（小时） */
    @Value("${loan.validation.scheduler.revalidationHours:24}")
    private int revalidationHours;

    /** 数据清理保留天数 */
    @Value("${loan.validation.scheduler.cleanupDays:30}")
    private int cleanupDays;

    /**
     * 定时批量验证任务
     * 每天凌晨2点执行
     */
    @Scheduled(cron = "${loan.validation.scheduler.batchValidationCron:0 0 2 * * ?}")
    public void scheduledBatchValidation() {
        if (!schedulerEnabled) {
            log.debug("定时验证任务已禁用，跳过执行");
            return;
        }

        log.info("开始执行定时批量验证任务，执行时间: {}", DateUtils.getTime());

        try {
            // 发布批量验证请求事件
            LoanChangeEvent batchValidationEvent = LoanChangeEvent.createBatchValidationRequestEvent(
                this, "系统定时任务");
            eventPublisher.publishEvent(batchValidationEvent);

            log.info("定时批量验证任务触发完成");

        } catch (Exception e) {
            log.error("定时批量验证任务执行失败", e);
        }
    }

    /**
     * 定时检查需要重新验证的贷款
     * 每小时执行一次
     */
    @Scheduled(cron = "${loan.validation.scheduler.revalidationCheckCron:0 0 * * * ?}")
    public void scheduledRevalidationCheck() {
        if (!schedulerEnabled) {
            log.debug("重新验证检查任务已禁用，跳过执行");
            return;
        }

        log.info("开始执行定时重新验证检查任务，执行时间: {}", DateUtils.getTime());

        try {
            // 获取需要重新验证的贷款列表
            List<Long> loansNeedRevalidation = getLoansNeedRevalidation();

            if (loansNeedRevalidation.isEmpty()) {
                log.info("没有需要重新验证的贷款记录");
                return;
            }

            log.info("发现需要重新验证的贷款数量: {}", loansNeedRevalidation.size());

            // 分批添加到验证队列
            int processedCount = 0;
            for (Long loanId : loansNeedRevalidation) {
                try {
                    validationQueueManager.addToValidationQueue(loanId, 
                        ValidationQueueManager.Priority.LOW, "定时重新验证检查");
                    processedCount++;
                } catch (Exception e) {
                    log.error("添加重新验证任务到队列失败，贷款ID: {}", loanId, e);
                }
            }

            log.info("定时重新验证检查任务完成，处理数量: {}/{}", processedCount, loansNeedRevalidation.size());

        } catch (Exception e) {
            log.error("定时重新验证检查任务执行失败", e);
        }
    }

    /**
     * 定时清理过期验证记录
     * 每天凌晨3点执行
     */
    @Scheduled(cron = "${loan.validation.scheduler.cleanupCron:0 0 3 * * ?}")
    public void scheduledCleanupExpiredValidations() {
        if (!schedulerEnabled) {
            log.debug("数据清理任务已禁用，跳过执行");
            return;
        }

        log.info("开始执行定时数据清理任务，执行时间: {}, 保留天数: {}", DateUtils.getTime(), cleanupDays);

        try {
            int deletedCount = loanConsistencyService.cleanupExpiredValidations(cleanupDays);
            log.info("定时数据清理任务完成，清理记录数: {}", deletedCount);

        } catch (Exception e) {
            log.error("定时数据清理任务执行失败", e);
        }
    }

    /**
     * 定时监控队列状态
     * 每10分钟执行一次
     */
    @Scheduled(cron = "${loan.validation.scheduler.queueMonitorCron:0 */10 * * * ?}")
    public void scheduledQueueMonitor() {
        if (!schedulerEnabled) {
            return;
        }

        try {
            Map<String, Object> queueStatus = validationQueueManager.getQueueStatus();
            
            int priorityQueueSize = (Integer) queueStatus.get("priorityQueueSize");
            int delayQueueSize = (Integer) queueStatus.get("delayQueueSize");
            int processingTasksCount = (Integer) queueStatus.get("processingTasksCount");
            int maxQueueSize = (Integer) queueStatus.get("maxQueueSize");

            // 记录队列状态
            log.debug("验证队列状态监控 - 优先级队列: {}, 延迟队列: {}, 处理中: {}, 最大容量: {}", 
                priorityQueueSize, delayQueueSize, processingTasksCount, maxQueueSize);

            // 检查队列是否接近满载
            double queueUsageRate = (double) priorityQueueSize / maxQueueSize;
            if (queueUsageRate > 0.8) {
                log.warn("验证队列使用率过高: {:.2f}%, 当前队列大小: {}, 最大容量: {}", 
                    queueUsageRate * 100, priorityQueueSize, maxQueueSize);
            }

            // 检查是否有长时间处理的任务
            if (processingTasksCount > 0) {
                log.debug("当前有 {} 个任务正在处理中", processingTasksCount);
            }

        } catch (Exception e) {
            log.error("队列状态监控任务执行失败", e);
        }
    }

    /**
     * 定时清理异步验证任务
     * 每小时执行一次
     */
    @Scheduled(cron = "0 0 * * * ?")
    public void scheduledAsyncTaskCleanup() {
        if (!schedulerEnabled) {
            return;
        }

        log.debug("开始执行异步验证任务清理，执行时间: {}", DateUtils.getTime());

        try {
            // 这里需要注入AsyncValidationService来执行清理
            // 由于循环依赖问题，暂时通过ApplicationContext获取
            // AsyncValidationServiceImpl asyncValidationService = 
            //     ApplicationContextUtils.getBean(AsyncValidationServiceImpl.class);
            // asyncValidationService.cleanupCompletedTasks();
            
            log.debug("异步验证任务清理完成");

        } catch (Exception e) {
            log.error("异步验证任务清理失败", e);
        }
    }

    /**
     * 定时健康检查
     * 每30分钟执行一次
     */
    @Scheduled(cron = "${loan.validation.scheduler.healthCheckCron:0 */30 * * * ?}")
    public void scheduledHealthCheck() {
        if (!schedulerEnabled) {
            return;
        }

        log.debug("开始执行验证系统健康检查，执行时间: {}", DateUtils.getTime());

        try {
            // 检查验证服务是否正常
            boolean serviceHealthy = checkValidationServiceHealth();
            
            // 检查队列管理器是否正常
            boolean queueHealthy = checkQueueManagerHealth();

            if (serviceHealthy && queueHealthy) {
                log.debug("验证系统健康检查通过");
            } else {
                log.warn("验证系统健康检查发现问题 - 验证服务: {}, 队列管理器: {}", 
                    serviceHealthy ? "正常" : "异常", queueHealthy ? "正常" : "异常");
            }

        } catch (Exception e) {
            log.error("验证系统健康检查执行失败", e);
        }
    }

    /**
     * 获取需要重新验证的贷款列表
     * 
     * @return 需要重新验证的贷款ID列表
     */
    private List<Long> getLoansNeedRevalidation() {
        try {
            // 这里可以调用mapper方法获取需要重新验证的贷款
            // 暂时使用service方法的逻辑
            List<Long> allLoans = loanConsistencyService.getValidatedLoanList(null);
            return allLoans.stream()
                .filter(loanId -> loanConsistencyService.needsRevalidation(loanId))
                .limit(batchSize)
                .collect(Collectors.toList());
                
        } catch (Exception e) {
            log.error("获取需要重新验证的贷款列表失败", e);
            return new ArrayList<>();
        }
    }

    /**
     * 检查验证服务健康状态
     * 
     * @return 是否健康
     */
    private boolean checkValidationServiceHealth() {
        try {
            // 执行一个简单的验证操作来检查服务状态
            Map<String, Object> statistics = loanConsistencyService.getValidationStatistics(null, null);
            return statistics != null && !statistics.containsKey("error");
            
        } catch (Exception e) {
            log.error("验证服务健康检查失败", e);
            return false;
        }
    }

    /**
     * 检查队列管理器健康状态
     * 
     * @return 是否健康
     */
    private boolean checkQueueManagerHealth() {
        try {
            Map<String, Object> queueStatus = validationQueueManager.getQueueStatus();
            Boolean running = (Boolean) queueStatus.get("running");
            return running != null && running;
            
        } catch (Exception e) {
            log.error("队列管理器健康检查失败", e);
            return false;
        }
    }

    /**
     * 手动触发批量验证
     * 
     * @return 触发结果
     */
    public Map<String, Object> triggerManualBatchValidation() {
        log.info("手动触发批量验证任务，触发时间: {}", DateUtils.getTime());

        try {
            // 发布批量验证请求事件
            LoanChangeEvent batchValidationEvent = LoanChangeEvent.createBatchValidationRequestEvent(
                this, "手动触发");
            eventPublisher.publishEvent(batchValidationEvent);

            Map<String, Object> result = new HashMap<>();
            result.put("success", true);
            result.put("message", "批量验证任务已触发");
            result.put("triggerTime", DateUtils.getTime());
            return result;

        } catch (Exception e) {
            log.error("手动触发批量验证任务失败", e);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("message", "批量验证任务触发失败: " + e.getMessage());
            result.put("triggerTime", DateUtils.getTime());
            return result;
        }
    }

    /**
     * 获取调度器状态
     * 
     * @return 调度器状态信息
     */
    public Map<String, Object> getSchedulerStatus() {
        Map<String, Object> status = new HashMap<>();
        status.put("enabled", schedulerEnabled);
        status.put("batchSize", batchSize);
        status.put("revalidationHours", revalidationHours);
        status.put("cleanupDays", cleanupDays);
        status.put("currentTime", DateUtils.getTime());
        return status;
    }
}