package com.tuoheng.admin.task;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.tuoheng.admin.entity.Inspection;
import com.tuoheng.admin.entity.InspectionCycle;
import com.tuoheng.admin.enums.InspectionStatusEnum;
import com.tuoheng.admin.enums.InspectionTaskTypeEnum;
import com.tuoheng.admin.enums.InspectionTypeEnum;
import com.tuoheng.admin.enums.MarkEnum;
import com.tuoheng.admin.mapper.InspectionCycleMapper;
import com.tuoheng.admin.mapper.InspectionMapper;
import com.tuoheng.admin.utils.InspectionCycleNextTimeUtil;
import com.tuoheng.common.core.utils.DateUtils;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
 * @Author: 吴彬
 * @CreateTime: 2023-06-14  15:24
 * @Description: 定时扫描机场周期性任务
 * @Version: 1.0
 */
@Slf4j
@Component
public class InspectionCycleTask {

    @Resource
    private InspectionMapper inspectionMapper;

    @Resource
    private InspectionCycleMapper inspectionCycleMapper;

    /**
     * 机场周期性任务定时器
     */
    @XxlJob("inspectionCycleTaskHandler")
    public void inspectionExecuteHandler() {
        log.info("=================================开始执行场周期性任务定时器任务调度=================================");

        /**
         * 1、查询所有状态为默认状态的周期性任务
         * 2、遍历周期性任务，根据周期性任务的下次执行时间判断是否需要执行
         * 3、调用执行任务方法
         * 4、计算任务下次执行时间，更新任务下次执行时间
         */
        Date today = null;
        try {
            today = DateUtils.parseDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, DateUtils.now()), DateUtils.YYYY_MM_DD);
        } catch (Exception e) {
            log.error("获取开始时间异常：{}", e);
        }
        List<InspectionCycle> inspectionCycleList = inspectionCycleMapper.selectList(new LambdaQueryWrapper<InspectionCycle>()
                .le(InspectionCycle::getCycleStartTime, today)
                .ge(InspectionCycle::getCycleEndTime, today)
                .eq(InspectionCycle::getIsEnable, 1)
                .eq(InspectionCycle::getMark, MarkEnum.VALID.getCode()));
        Inspection inspection;
        for (InspectionCycle inspectionCycle : inspectionCycleList) {
            inspection = inspectionMapper.selectOne(Wrappers.<Inspection>lambdaQuery()
                    .eq(Inspection::getTenantId, inspectionCycle.getTenantId())
                    .eq(Inspection::getInspectionCycleId, inspectionCycle.getId())
                    .eq(Inspection::getMark, MarkEnum.VALID.getCode())
                    .orderByDesc(Inspection::getCreateTime)
                    .last("limit 1"));
            if (ObjectUtil.isNotEmpty(inspection)) {
                String date1 = DateUtils.dateTime(inspectionCycle.getCycleEndTime());
                String date2 = DateUtils.dateTime(inspection.getInspectionTime());
                int compare = DateUtils.compareToDate(date1, date2);
                if (2 != compare) {
                    log.info("最后一天，已生成过对应的子任务, inspectionCycleId={}, inspectionId={}", inspectionCycle.getId(), inspection.getId());
                    continue;
                }
                if (InspectionStatusEnum.WAIT_FLIGHT.getCode() == inspection.getStatus()) {
                    log.info("已生成下一个周期待执行的任务, inspectionId={}", inspection.getId());
                    continue;
                }
            }
            // 生成下一次的周期子任务
            // ADD: 若原下次子任务被取消(状态=16），则继续生成下下次任务
            Date startDateTime = null;
            Date nowTime = DateUtils.now();
            if(ObjectUtil.isNotNull(inspection)){
                startDateTime = DateUtils.addDateTimeToDate(inspection.getInspectionTime(),1,0,0,0);
                if(startDateTime.before(nowTime)) {
                    startDateTime = nowTime;
                }
            }
            else{
                startDateTime = nowTime;
            }
            inspection = this.buildInspection(inspectionCycle, startDateTime);
            // 若生成的下次子任务时间已超出周期任务的有效期范围，则不生成子任务
            if (ObjectUtil.isNotNull(inspection) && inspection.getInspectionTime().after(inspectionCycle.getCycleEndTime())) {
                log.info("生成的下一个周期子任务已超出有效期范围，生成无效：inspectionTime={}，cycleEndTime={}",
                        DateUtil.format(inspection.getInspectionTime(), DatePattern.NORM_DATETIME_PATTERN),
                        DateUtil.format(inspectionCycle.getCycleEndTime(), DatePattern.NORM_DATETIME_PATTERN));
                continue;
            }
            Integer count = inspectionMapper.insert(inspection);
            if (count <= 0) {
                log.info("生成下一个周期待执行的任务失败：inspectionCycleId={}", inspectionCycle.getId());
            } else {
                log.info("生成下一个周期待执行的任务成功：inspectionId={}", inspection.getId());
            }
        }
        log.info("=================================结束执行场周期性任务定时器任务调度=================================");
    }

    // 从startDateTime开始生成下次子任务
    private Inspection buildInspection(InspectionCycle inspectionCycle, Date startDateTime) {
        Inspection inspection = new Inspection();
        String code = inspectionCycle.getCode() + RandomUtil.randomNumbers(3);
        inspection.setCode(code);
        // 改为“周期任务名称-” + 当前周期任务递增数，如“周期任务ABC-2”
        Integer subTaskCount = inspectionMapper.selectCount(Wrappers.<Inspection>lambdaQuery()
                .eq(Inspection::getTenantId, inspectionCycle.getTenantId()) // 租户ID
                .eq(Inspection::getInspectionCycleId, inspectionCycle.getId())  // 周期任务ID
                .eq(Inspection::getType, "0") // 周期任务类型
        );
        if (subTaskCount == null || subTaskCount == 0) {
            inspection.setName(inspectionCycle.getName() + "-" + 1);
        } else {
            inspection.setName(inspectionCycle.getName() + "-" + (subTaskCount + 1));
        }
        inspection.setTenantId(inspectionCycle.getTenantId());
        inspection.setDeptId(inspectionCycle.getDeptId());
        inspection.setRoadId(inspectionCycle.getRoadId());
        inspection.setSectionId(inspectionCycle.getSectionId());
        inspection.setInspectionCycleId(inspectionCycle.getId());
        inspection.setAirportId(inspectionCycle.getAirportId());
        inspection.setDroneId(inspectionCycle.getDroneId());
        inspection.setInspectionLine(inspectionCycle.getAirportLineId());
        inspection.setInspectionTime(inspectionCycle.getCycleNextTime());
        inspection.setType(InspectionTaskTypeEnum.CYCLE_INSPECTION.getCode());
        inspection.setInspectionType(InspectionTypeEnum.AIRPORT.getCode());
        inspection.setCreateUser(inspectionCycle.getCreateUser());

        inspection.setCreateTime(DateUtils.now());
        inspection.setStatus(InspectionStatusEnum.WAIT_FLIGHT.getCode());
        Date cycleNextTime = InspectionCycleNextTimeUtil.getCycleNextTime(inspectionCycle.getType(),
                startDateTime,
                inspectionCycle.getCycleTime(),
                inspectionCycle.getCycleFrequency());
        inspection.setInspectionTime(cycleNextTime);
        inspection.setIsLive(1);  // 机场巡逻，只有直播，将isLive设置为1
        return inspection;
    }

}
