package com.fs.watch.scheduled;

import com.alibaba.fastjson.JSONObject;
import com.fs.common.utils.DateUtils;
import com.fs.his.dto.HealthHistoryDTO;
import com.fs.his.service.IFsHealthTongueService;
import com.fs.his.vo.FsHealthTongueUVO;
import com.fs.watch.domain.*;
import com.fs.watch.domain.vo.WatchUserAndHealthVo;
import com.fs.watch.param.WatchSetUpSendParam;
import com.fs.watch.service.*;
import com.fs.watch.utils.MyDateTimeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ScheduledFuture;
import java.util.stream.Collectors;

@Component
@Slf4j
public class DynamicSendTestTask {

    private final ThreadPoolTaskScheduler taskScheduler;
    private final WatchSendMsgSetService watchSendMsgSetService;
    private final WatchUserService watchUserService;
    private final WatchMsgSetService watchMsgSetService;
    private final DeviceSetUpService deviceSetUpService;
    private final WatchBloodGlucoseDataService watchBloodGlucoseDataService;
    private final WatchThirdBpDataService watchThirdBpDataService;
    private final IFsHealthTongueService fsHealthTongueService;
    private final ThreadPoolTaskExecutor threadPoolTaskExecutor; // 注入线程池
    private final WatchSendMsgLogService watchSendMsgLogService;

    // 使用构造器注入
    @Autowired
    public DynamicSendTestTask(ThreadPoolTaskScheduler taskScheduler,
                               WatchSendMsgSetService watchSendMsgSetService,
                               WatchUserService watchUserService,
                               WatchMsgSetService watchMsgSetService,
                               DeviceSetUpService deviceSetUpService,
                               WatchBloodGlucoseDataService watchBloodGlucoseDataService,
                               WatchThirdBpDataService watchThirdBpDataService,
                               IFsHealthTongueService fsHealthTongueService,
                               ThreadPoolTaskExecutor threadPoolTaskExecutor,
                               WatchSendMsgLogService watchSendMsgLogService) {
        this.taskScheduler = taskScheduler;
        this.watchSendMsgSetService = watchSendMsgSetService;
        this.watchMsgSetService = watchMsgSetService;
        this.watchUserService = watchUserService;
        this.deviceSetUpService = deviceSetUpService;
        this.watchBloodGlucoseDataService = watchBloodGlucoseDataService;
        this.watchThirdBpDataService = watchThirdBpDataService;
        this.fsHealthTongueService = fsHealthTongueService;
        this.threadPoolTaskExecutor = threadPoolTaskExecutor;
        this.watchSendMsgLogService = watchSendMsgLogService;
        log.info("ThreadPoolTaskScheduler 初始化完成");
    }


    private ScheduledFuture<?> startTask;
    private ScheduledFuture<?> endTask;
    private ScheduledFuture<?> testTask;


    // 在项目启动时执行此方法，自动从数据库获取参数并执行调度任务
    @PostConstruct
    public void init() {
        // 从数据库获取参数，假设我们只查询一条记录
        WatchSendMsgSet set = watchSendMsgSetService.selectWatchSendMsgSetByType("test");  // 根据你的实际情况修改
        if (set != null) {
            WatchSetUpSendParam param = new WatchSetUpSendParam();
            param.setFlag(set.getStatus() == 1);
            param.setStart(set.getStart());
            param.setEnd(set.getEnd());
            log.info("项目启动时，自动执行检测提醒设置调度任务，参数: {}", param);
            testTask(param);

        } else {
            log.warn("数据库未找到调度参数");
        }
    }

    /**
     * 调度任务，根据参数决定是开启还是关闭任务
     *
     * @param param 请求参数
     */
    public void testTask(WatchSetUpSendParam param) {
        log.info("testTask 被调用，参数: {}", param);

        // 参数校验
        if (param == null) {
            throw new IllegalArgumentException("参数不能为空");
        }

        if (!Boolean.TRUE.equals(param.getFlag())) {
            // 如果 flag 为 false，取消任务
            cancelAllTasks();
            return;
        }

        // flag 为 true，继续调度任务
        LocalTime startTime;
        LocalTime endTime;

        try {
            startTime = LocalTime.parse(param.getStart());
            endTime = LocalTime.parse(param.getEnd());
            log.info("解析后的开始时间: {}, 结束时间: {}", startTime, endTime);
        } catch (Exception e) {
            log.error("时间格式错误，正确格式为 'HH:mm:ss': {}", e.getMessage());
            throw new IllegalArgumentException("时间格式错误");
        }

        if (startTime.isAfter(endTime)) {
            throw new IllegalArgumentException("开始时间不能晚于结束时间");
        }

        // 取消之前的任务（如果有）
        cancelAllTasks();

        // 检查当前时间是否在开始时间和结束时间之间
        LocalTime now = LocalTime.now();
        if (now.isAfter(startTime) && now.isBefore(endTime)) {
            log.info("检测提醒当前时间在开始时间和结束时间之间，立即启动周期性任务");
            startPeriodicTask();
        }

        // 生成 CRON 表达式并调试输出
        log.info("生成的开始任务 CRON 表达式: {}", String.format("%d %d %d * * ?", startTime.getSecond(), startTime.getMinute(), startTime.getHour()));
        log.info("生成的结束任务 CRON 表达式: {}", String.format("%d %d %d * * ?", endTime.getSecond(), endTime.getMinute(), endTime.getHour()));

        // 调度每天开始和结束的任务
        startTask = taskScheduler.schedule(() -> {
            log.info("检测提醒开始任务触发，当前时间: {}", LocalTime.now());
            startPeriodicTask();
        }, toDailyTrigger(startTime));

        endTask = taskScheduler.schedule(() -> {
            log.info("检测提醒结束任务触发，当前时间: {}", LocalTime.now());
            stopPeriodicTask();
        }, toDailyTrigger(endTime));
    }

    /**
     * 开始周期性任务
     */
    private void startPeriodicTask() {
        if (testTask == null || testTask.isCancelled()) {
            log.info("检测提醒周期性任务已启动，当前时间: {}", LocalTime.now());
            sendTestMsg(); //执行一次就结束
        } else {
            System.out.println("检测提醒周期性任务已经存在且正在运行，当前时间: " + LocalTime.now());
        }
    }

    /**
     * 停止周期性任务
     */
    private void stopPeriodicTask() {
        if (testTask != null) {
            testTask.cancel(false);
            testTask = null;
            log.info("检测提醒周期性任务已停止，当前时间: {}", LocalTime.now());
        }
    }

    /**
     * 取消所有任务
     */
    private void cancelAllTasks() {
        if (startTask != null) {
            startTask.cancel(false);
            startTask = null;
        }
        if (endTask != null) {
            endTask.cancel(false);
            endTask = null;
        }
        stopPeriodicTask(); // 同时停止周期性任务
    }

    // 使用cron表达式设置每天上午10点执行提醒测试任务
//    @Scheduled(cron = "0 0 10 * * ?")
    public void sendTestMsg() {
        //1.查询需要发送的设备
        List<WatchUserAndHealthVo> watchUserAndHealthVos = new ArrayList<>(watchUserService.listByDeviceIdNotNull());
        //2.获取提醒消息
        List<WatchMsgSet> watchMsgSets = watchMsgSetService.selectWatchMsgSetList(new WatchMsgSet(0, 2)); // 查询正常使用的检测提醒规则


        //3.发送消息
        if (watchMsgSets != null && !watchMsgSets.isEmpty() && !watchUserAndHealthVos.isEmpty()) {
            watchUserAndHealthVos.forEach(vo ->
                    threadPoolTaskExecutor.execute(() -> {
                        long startTime = System.currentTimeMillis();
                        final String deviceIds = vo.getDeviceId();
                        try {
                            processMessageSending(deviceIds, watchMsgSets, new WatchUserAndHealthVo(vo));
                        } catch (Exception e) {
                            log.error("Error processing message for device {}: {}", vo.getDeviceId(), e.getMessage(), e);
                        } finally {
                            log.info("Task for device {} completed in {} ms", deviceIds, System.currentTimeMillis() - startTime);
                        }
                    })
            );


        }


    }

    private void processMessageSending(String deviceIds, List<WatchMsgSet> watchMsgSets, WatchUserAndHealthVo watchUserAndHealthVo) {
        watchMsgSets.forEach(msgSet -> {
            HealthHistoryDTO historyDto = getHealthHistoryDTO(watchUserAndHealthVo);
            List<String> list = new ArrayList<>(Arrays.asList(deviceIds.split(",")));
            list.forEach(deviceId -> {
                String detailsType = "";
                try {
                    //3.1血糖检测
                    if ("血糖".equals(msgSet.getDetailsType())) {
                        detailsType = "血糖";
                        if (isSent(deviceId, detailsType)) return;
                        //查询上次检测时间
                        WatchBloodGlucoseData bgData = watchBloodGlucoseDataService.getLatest(deviceId);
                        if (bgData == null) {
                            //第一次发送
                            deviceSetUpService.message(deviceId, msgSet.getMsgTitle(), msgSet.getMsgDescription(), "test", 3, null, detailsType);
                            Thread.sleep(30 * 1000);
                        } else {
                            //非第一次 按规则发送
                            //计算时间差 小时
                            String lastTime = bgData.getCreateTime();
                            Long hour = MyDateTimeUtils.getTimeDif(lastTime, DateUtils.getTime(), "hour");
                            //判断是否糖尿病患者
                            if (historyDto == null) {
                                if (hour != null && hour >= msgSet.getNormalRule()) {
                                    deviceSetUpService.message(deviceId, msgSet.getMsgTitle(), msgSet.getMsgDescription(), "test", 3, null, detailsType);
                                    Thread.sleep(30 * 1000);
                                }
                            } else {
                                if ((historyDto.getValue()).contains("糖尿病")) {
                                    //判断是否到发送时间
                                    if (hour != null && hour >= msgSet.getAbnormalRule()) {
                                        deviceSetUpService.message(deviceId, msgSet.getMsgTitle(), msgSet.getMsgDescription(), "test", 3, null, detailsType);
                                        Thread.sleep(30 * 1000);
                                    }
                                } else {
                                    if (hour != null && hour >= msgSet.getNormalRule()) {
                                        deviceSetUpService.message(deviceId, msgSet.getMsgTitle(), msgSet.getMsgDescription(), "test", 3, null, detailsType);
                                        Thread.sleep(30 * 1000);
                                    }
                                }
                            }


                        }
                    } else if ("血压".equals(msgSet.getDetailsType())) {
                        //3.2血压检测
                        detailsType = "血压";
                        if (isSent(deviceId, detailsType)) return;
                        WatchThirdBpData bpData = watchThirdBpDataService.getLatest(deviceId);
                        //3.1.1发送消息
                        if (bpData == null) {
                            //第一次发送
                            deviceSetUpService.message(deviceId, msgSet.getMsgTitle(), msgSet.getMsgDescription(), "test", 3, null, detailsType);
                            Thread.sleep(30 * 1000);
                        } else {
                            //非第一次 按规则发送
                            //计算时间差 小时
                            String lastTime = bpData.getCreateTime();
                            Long hour = MyDateTimeUtils.getTimeDif(lastTime, DateUtils.getTime(), "hour");
                            if (historyDto == null) {
                                if (hour != null && hour >= msgSet.getNormalRule()) {
                                    deviceSetUpService.message(deviceId, msgSet.getMsgTitle(), msgSet.getMsgDescription(), "test", 3, null, detailsType);
                                    Thread.sleep(30 * 1000);
                                }
                            } else {
                                //判断是否高血压患者
                                if ((historyDto.getValue()).contains("高血压")) {
                                    //判断是否到发送时间
                                    if (hour != null && hour >= msgSet.getAbnormalRule()) {
                                        deviceSetUpService.message(deviceId, msgSet.getMsgTitle(), msgSet.getMsgDescription(), "test", 3, null, detailsType);
                                        Thread.sleep(30 * 1000);
                                    }
                                } else {
                                    if (hour != null && hour >= msgSet.getNormalRule()) {
                                        deviceSetUpService.message(deviceId, msgSet.getMsgTitle(), msgSet.getMsgDescription(), "test", 3, null, detailsType);
                                        Thread.sleep(30 * 1000);
                                    }
                                }
                            }
                        }
                    } else if ("舌诊".equals(msgSet.getDetailsType())) {
                        //3.2舌诊检测
                        detailsType = "舌诊";
                        if (isSent(deviceId, detailsType)) return;
                        FsHealthTongueUVO fsHealthTongueUVO = fsHealthTongueService.selectFsHealthTongueByUserId(watchUserAndHealthVo.getUserId());
                        //3.1.1发送消息
                        if (fsHealthTongueUVO == null) {
                            //第一次发送
                            deviceSetUpService.message(deviceId, msgSet.getMsgTitle(), msgSet.getMsgDescription(), "test", 3, null, detailsType);
                            Thread.sleep(30 * 1000);
                        } else {
                            //非第一次 按规则发送
                            //计算时间差 小时
                            Date lastSendTime = fsHealthTongueUVO.getCreateTime();
                            Long hour = MyDateTimeUtils.getTimeDif(lastSendTime, DateUtils.getNowDate(), "hour");
                            //判断是否到发送时间
                            if (hour != null && hour >= msgSet.getNormalRule()) {
                                deviceSetUpService.message(deviceId, msgSet.getMsgTitle(), msgSet.getMsgDescription(), "test", 3, null, detailsType);
                                Thread.sleep(30 * 1000);
                            }
                        }
                    }
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            });


        });
    }

    private boolean isSent(String deviceId, String detailsType) {
        //检查当天是否已发送
        WatchSendMsgLog watchSendMsgLog = watchSendMsgLogService.selectLastByMsgTypeAndDeviceIdAndDetailsType(2, deviceId, detailsType);
        if (watchSendMsgLog != null) {
            LocalDate operDate = watchSendMsgLog.getOperTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            LocalDate today = LocalDate.now();
            // 比较两个日期是否相同
            boolean isToday = operDate.equals(today);
            if (isToday) {
                return true;
            }
        }
        return false;
    }

    private static HealthHistoryDTO getHealthHistoryDTO(WatchUserAndHealthVo watchUserAndHealthVo) {
        HealthHistoryDTO historyDto = null;
        String healthHistory = watchUserAndHealthVo.getHealthHistory();
        if (healthHistory != null && !healthHistory.isEmpty()) {
            List<HealthHistoryDTO> list = JSONObject.parseArray(healthHistory, HealthHistoryDTO.class);
            if (list != null && !list.isEmpty()) {
                List<HealthHistoryDTO> collect = list.stream().filter(temp -> temp.getName().contains("目前是否有以下疾病（多选）")).collect(Collectors.toList());
                if (!collect.isEmpty()) {
                    historyDto = collect.get(0);
                }
            }

        }
        return historyDto;
    }

    /**
     * 将 LocalTime 转换为每日触发器
     *
     * @param time 目标时间
     * @return Runnable 的触发时间
     */
    private Trigger toDailyTrigger(LocalTime time) {
        // Cron 表达式格式: 秒 分 时 日 月 星期
        String cronExpression = String.format("%d %d %d * * ?",
                time.getSecond(),
                time.getMinute(),
                time.getHour());
        return new CronTrigger(cronExpression);
    }

}

