package com.ruoyi.robot.task;

import java.time.Instant;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


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.scheduling.support.SimpleTriggerContext;
import org.springframework.stereotype.Component;
import org.springframework.scheduling.support.CronTrigger;

import java.time.Instant;
import java.util.Date;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.mqtt.service.MqttSendService;
import com.ruoyi.robot.domain.LdTask;
import com.ruoyi.robot.domain.LdTaskExecutionLog;
import com.ruoyi.robot.service.ILdTaskExecutionLogService;
import com.ruoyi.robot.service.ILdTaskService;
/**
 * 定时任务调度器
 * 负责检查和执行定时任务
 */
@Component
public class LdTaskScheduler {

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

    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);

    // 今日已执行的任务缓存（任务ID -> 执行时间）
    private final ConcurrentHashMap<Long, Date> executedTasksToday = new ConcurrentHashMap<>();

    // 最后清理日期
    private long lastCleanupDate = 0;

    @Autowired
    private ILdTaskService ldTaskService;

    @Autowired
    private ILdTaskExecutionLogService ldTaskExecutionLogService;

    @Autowired(required = false)
    private MqttSendService mqttSendService;

    @Value("${mqtt.deviceId:ld000001}")
    private String defaultDeviceId;

    /**
     * 启动定时任务检查
     */
    public void start() {
        // 每分钟检查一次待执行的任务
        scheduler.scheduleAtFixedRate(() -> {
            try {
                checkAndExecuteScheduledTasks();
            } catch (Exception e) {
                log.error("检查定时任务异常", e);
            }
        }, 0, 1, TimeUnit.MINUTES);

        // 每天凌晨清理已执行记录
        scheduler.scheduleAtFixedRate(() -> {
            try {
                cleanupExecutedTasksCache();
            } catch (Exception e) {
                log.error("清理定时任务缓存异常", e);
            }
        }, 0, 1, TimeUnit.HOURS);

        log.info("定时任务调度器已启动");
    }

    /**
     * 检查并执行到期的定时任务
     */
    private void checkAndExecuteScheduledTasks() {
        // 每天零点重置缓存
        cleanupDailyCacheIfNeeded();

        // 获取待执行的定时任务
        List<LdTask> pendingTasks = ldTaskService.selectPendingScheduledTasks();

        if (pendingTasks == null || pendingTasks.isEmpty()) {
            return;
        }

        Date now = new Date();
        int currentHour = now.getHours();
        int currentMinute = now.getMinutes();
        int currentDayOfWeek = now.getDay(); // 0=周日, 1=周一, ...

        for (LdTask task : pendingTasks) {
            try {
                // 检查任务是否应该现在执行
                if (shouldExecuteNow(task, currentHour, currentMinute, currentDayOfWeek)) {
                    // 检查是否今日已执行
                    if (executedTasksToday.containsKey(task.getId())) {
                        log.debug("任务 {} 已于今日执行过，跳过", task.getTaskName());
                        continue;
                    }

                    log.info("执行定时任务: {} (地图: {})", task.getTaskName(), task.getMapName());
                    executeTask(task);

                    // 标记为已执行
                    executedTasksToday.put(task.getId(), now);
                }
            } catch (Exception e) {
                log.error("处理定时任务 {} 异常", task.getTaskName(), e);
            }
        }
    }

    /**
     * 判断任务是否应该现在执行
     */
    private boolean shouldExecuteNow(LdTask task, int currentHour, int currentMinute, int currentDayOfWeek) {
        // 检查Cron表达式或执行时间
        String executeTime = task.getExecuteTime();
        String executeWeekdays = task.getExecuteWeekdays();

        if (executeTime == null || executeTime.isEmpty()) {
            return false;
        }

        // 解析执行时间
        String[] timeParts = executeTime.split(":");
        if (timeParts.length < 2) {
            return false;
        }

        int taskHour;
        int taskMinute;
        try {
            taskHour = Integer.parseInt(timeParts[0]);
            taskMinute = Integer.parseInt(timeParts[1]);
        } catch (NumberFormatException e) {
            return false;
        }

        // 检查时间是否匹配（允许1分钟误差）
        if (currentHour != taskHour || Math.abs(currentMinute - taskMinute) > 1) {
            return false;
        }

        // 检查星期几
        if (executeWeekdays != null && !executeWeekdays.isEmpty()) {
            String[] weekdays = executeWeekdays.split(",");
            boolean dayMatch = false;
            for (String day : weekdays) {
                int dayValue = Integer.parseInt(day.trim());
                // 转换：前端1-7(周一到周日) -> 后端1-7(周一到周日)，但Calendar的dayOfWeek是1=周日
                if (dayValue == 1 && currentDayOfWeek == 0) {
                    dayMatch = true;
                    break;
                } else if (dayValue == currentDayOfWeek) {
                    dayMatch = true;
                    break;
                }
            }
            if (!dayMatch) {
                return false;
            }
        } else {
            // 没有指定星期，默认每天执行
        }

        return true;
    }

    /**
     * 执行任务
     */
    private void executeTask(LdTask task) {
        String deviceId = task.getDeviceId() != null ? task.getDeviceId() : defaultDeviceId;

        // 创建执行记录
        LdTaskExecutionLog logTask = new LdTaskExecutionLog();
        logTask.setTaskId(task.getId());
        logTask.setTaskName(task.getTaskName());
        logTask.setMapName(task.getMapName());
        logTask.setExecuteTime(new Date());
        logTask.setStatus("running");
        logTask.setDeviceId(deviceId);

        // 解析目标点数量
        try {
            if (task.getWaypointCoords() != null) {
                JSONArray coords = JSON.parseArray(task.getWaypointCoords());
                logTask.setTotalWaypoints(coords.size());
            }
        } catch (Exception e) {
            log.warn("解析目标点数量失败", e);
        }

        ldTaskExecutionLogService.insertLdTaskExecutionLog(logTask);

        // 更新任务状态为运行中
        ldTaskService.updateTaskStatus(task.getId(), "running");

        // 通过MQTT发送任务执行指令
        try {
            if (mqttSendService != null) {
                // 构建任务数据并发送
                String taskName = task.getTaskName();
                boolean sendResult = mqttSendService.startTask(task.getMapName(), taskName);

                if (!sendResult) {
                    log.warn("MQTT发送任务启动指令失败: {}", taskName);
                }
            }
        } catch (Exception e) {
            log.error("发送MQTT任务指令异常", e);
        }
    }

    /**
     * 任务执行完成回调
     */
    public void onTaskCompleted(Long taskId, String status, String errorMessage) {
        try {
            LdTask task = ldTaskService.selectLdTaskById(taskId);
            if (task == null) {
                return;
            }

            // 更新任务状态
            String newStatus = "completed".equals(status) ? "idle" : "failed";
            ldTaskService.updateTaskStatus(taskId, newStatus);

            // 更新执行记录
            List<LdTaskExecutionLog> logs = ldTaskExecutionLogService.selectLdTaskExecutionLogByTaskId(taskId);
            if (logs != null && !logs.isEmpty()) {
                LdTaskExecutionLog latestLog = logs.get(0);
                if ("running".equals(latestLog.getStatus())) {
                    latestLog.setEndTime(new Date());
                    latestLog.setStatus(status);
                    if (errorMessage != null) {
                        latestLog.setErrorMessage(errorMessage);
                    }
                    ldTaskExecutionLogService.updateLdTaskExecutionLog(latestLog);
                }
            }

            // 更新任务统计
            task.setLastExecuteTime(new Date());
            task.setLastExecuteStatus(status);
            task.setTotalExecuteCount(task.getTotalExecuteCount() != null ? task.getTotalExecuteCount() + 1 : 1);

            // 计算下次执行时间
            if (task.getCronExpression() != null && !task.getCronExpression().isEmpty()) {
                task.setNextExecuteTime(calculateNextExecuteTime(task.getCronExpression()));
            }

            ldTaskService.updateLdTask(task);

        } catch (Exception e) {
            log.error("处理任务完成回调异常", e);
        }
    }

    /**
     * 每天零点清理缓存
     */
    private void cleanupDailyCacheIfNeeded() {
        long today = DateUtils.dateTimeNow("yyyyMMdd").hashCode();
        if (lastCleanupDate != today) {
            executedTasksToday.clear();
            lastCleanupDate = today;
            log.info("已清理定时任务执行缓存");
        }
    }

    /**
     * 每小时清理缓存（备用机制）
     */
    private void cleanupExecutedTasksCache() {
        long today = DateUtils.dateTimeNow("yyyyMMdd").hashCode();
        if (lastCleanupDate != today) {
            executedTasksToday.clear();
            lastCleanupDate = today;
        }
    }

    /**
     * 根据Cron表达式计算下次执行时间
     */
/*    private Date calculateNextExecuteTime(String cronExpression) {
        try {
            org.springframework.scheduling.support.CronTrigger cronTrigger =
                new org.springframework.scheduling.support.CronTrigger(cronExpression);
            return cronTrigger.nextExecutionTime(new java.util.Date());
        } catch (Exception e) {
            log.warn("解析Cron表达式失败: {}", cronExpression, e);
            return null;
        }
    }*/
    private Date calculateNextExecuteTime(String cronExpression) {
        try {
            CronTrigger cronTrigger = new CronTrigger(cronExpression);

            SimpleTriggerContext triggerContext = new SimpleTriggerContext();

            return cronTrigger.nextExecutionTime(triggerContext);

        } catch (Exception e) {
            log.warn("解析Cron表达式失败: {}", cronExpression, e);
            return null;
        }
    }

    /**
     * 停止调度器
     */
    public void stop() {
        scheduler.shutdown();
        log.info("定时任务调度器已停止");
    }
}
