package com.testor.common.util.cron;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cronutils.builder.CronBuilder;
import com.cronutils.model.Cron;
import com.cronutils.model.CronType;
import com.cronutils.model.definition.CronDefinitionBuilder;
import com.cronutils.model.field.expression.FieldExpression;
import com.cronutils.model.field.expression.FieldExpressionFactory;
import com.cronutils.model.field.value.SpecialChar;
import com.testor.xxl.job.task.config.XxlJobProperties;
import com.testor.xxl.job.task.module.job.model.*;
import com.testor.xxl.job.task.module.job.service.XxlJobService;
import com.testor.xxl.job.task.response.ListGetResponse;
import com.testor.xxl.job.task.response.ReturnT;
import com.testor.xxl.job.task.util.CronUtil;
import com.testor.xxl.job.task.util.DateTimeUtil;
import com.testor.xxl.job.task.util.WeekdayEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.sql.Time;
import java.time.*;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

@Slf4j
@Component
public class FrequencyUtil {

    @Autowired
    private XxlJobProperties xxlJobProperties;
    @Resource
    private XxlJobService xxlJobService;

    /**
     * 生成cron表达式(无提前时长)
     *
     * @param frequencyDTO
     * @return
     */
    public String generateCronByNoAdvance(FrequencyDTO frequencyDTO) {
        String frequencyKey = frequencyDTO.getFrequencyKey();
        if (StrUtil.isBlank(frequencyKey)) {
            return null;
        }

        String cronStr = null;
        // 单次
        if (CheckFrequencyEnum.one.getCode().equals(frequencyKey)) {
            String date = frequencyDTO.getDate();
            String time = frequencyDTO.getTime();
            String dateTimeStr = date + "T" + time;
            LocalDateTime dateTime = LocalDateTimeUtil.parse(dateTimeStr);
            cronStr = CronUtil.generateCronByOne(dateTime);
        }

        // 每小时
        if (CheckFrequencyEnum.hour.getCode().equals(frequencyKey)) {
            Integer minute = frequencyDTO.getMinute();
            Integer second = frequencyDTO.getSecond();
            cronStr = CronUtil.generateCronByEveryHour(second, minute);
        }

        // 每日
        if (CheckFrequencyEnum.day.getCode().equals(frequencyKey)) {
            String time = frequencyDTO.getTime();
            cronStr = CronUtil.generateCronByEveryDay(time);
        }

        // 每周
        if (CheckFrequencyEnum.week.getCode().equals(frequencyKey)) {
            String time = frequencyDTO.getTime();
            Integer weekday = frequencyDTO.getDayNum();
            List<WeekdayEnum> weekdayEnumList = new ArrayList<>();
            if (weekday == 1) {
                weekdayEnumList.add(WeekdayEnum.MONDAY);
            } else if (weekday == 2) {
                weekdayEnumList.add(WeekdayEnum.TUESDAY);
            } else if (weekday == 3) {
                weekdayEnumList.add(WeekdayEnum.WEDNESDAY);
            } else if (weekday == 4) {
                weekdayEnumList.add(WeekdayEnum.THURSDAY);
            } else if (weekday == 5) {
                weekdayEnumList.add(WeekdayEnum.FRIDAY);
            } else if (weekday == 6) {
                weekdayEnumList.add(WeekdayEnum.SATURDAY);
            } else if (weekday == 7) {
                weekdayEnumList.add(WeekdayEnum.SUNDAY);
            } else {
                return null;
            }
            cronStr = CronUtil.generateCronByEveryWeek(weekdayEnumList, time);
        }

        // 每月
        if (CheckFrequencyEnum.month.getCode().equals(frequencyKey)) {
            Integer monthday = frequencyDTO.getDayNum();
            String time = frequencyDTO.getTime();

            if (monthday != 0) {
                List<Integer> monthdayList = new ArrayList<>();
                monthdayList.add(monthday);
                cronStr = CronUtil.generateCronByEveryMonth(monthdayList, time);
            } else {
                cronStr = generateCronByLastDay(null, time);
            }
        }

        // 每季
        if (CheckFrequencyEnum.quarter.getCode().equals(frequencyKey)) {
            Integer monthNum = frequencyDTO.getMonthNum();
            Integer monthday = frequencyDTO.getDayNum();
            String time = frequencyDTO.getTime();
            List<Integer> monthNumList = new ArrayList<>();
            if (monthNum == 1) { // 每季 第一个月
                monthNumList.add(1);
                monthNumList.add(4);
                monthNumList.add(7);
                monthNumList.add(10);
            } else if (monthNum == 2) { // 每季 第二个月
                monthNumList.add(2);
                monthNumList.add(5);
                monthNumList.add(8);
                monthNumList.add(11);
            } else if (monthNum == 3) { // 每季 第三个月
                monthNumList.add(3);
                monthNumList.add(6);
                monthNumList.add(9);
                monthNumList.add(12);
            } else {
                return null;
            }
            monthNumList.add(monthNum);

            if (monthday != 0) {
                List<Integer> monthdayList = new ArrayList<>();
                monthdayList.add(monthday);
                cronStr = CronUtil.generateCronByEveryYear(monthNumList, monthdayList, time);
            } else {
                cronStr = CronUtil.generateCronByLastDay(monthNumList, time);
            }
        }

        // 每年
        if (CheckFrequencyEnum.year.getCode().equals(frequencyKey)) {
            Integer monthNum = frequencyDTO.getMonthNum();
            Integer monthday = frequencyDTO.getDayNum();
            String time = frequencyDTO.getTime();

            List<Integer> monthNumList = new ArrayList<>();
            monthNumList.add(monthNum);
            if (monthday != 0) {
                List<Integer> monthdayList = new ArrayList<>();
                monthdayList.add(monthday);
                cronStr = CronUtil.generateCronByEveryMonth(monthdayList, time);
            } else {
                cronStr = CronUtil.generateCronByLastDay(monthNumList, time);
            }

        }
        return cronStr;
    }

    public static String generateCronByLastDay(List<Integer> monthArr, String startTime) {
        Time bidStartTime = DateTimeUtil.formatTime(startTime);
        if (bidStartTime == null) {
            throw new RuntimeException("时间格式有无，转换失败");
        } else {
            int hour = bidStartTime.getHours();
            int minute = bidStartTime.getMinutes();
            int second = bidStartTime.getSeconds();
            Cron cron;
            if (monthArr != null && monthArr.size() != 0) {
                List<FieldExpression> monthExpressionList = new ArrayList();
                Iterator var8 = monthArr.iterator();

                while(var8.hasNext()) {
                    Integer month = (Integer)var8.next();
                    monthExpressionList.add(FieldExpressionFactory.on(month));
                }
                cron = CronBuilder.cron(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ)).withYear(FieldExpressionFactory.always()).withDoM(FieldExpressionFactory.on(SpecialChar.L)).withMonth(FieldExpressionFactory.and(monthExpressionList)).withDoW(FieldExpressionFactory.questionMark()).withHour(FieldExpressionFactory.on(hour)).withMinute(FieldExpressionFactory.on(minute)).withSecond(FieldExpressionFactory.on(second)).instance();
            } else {
                cron = CronBuilder.cron(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ)).withYear(FieldExpressionFactory.always()).withDoM(FieldExpressionFactory.on(SpecialChar.L)).withMonth(FieldExpressionFactory.always()).withDoW(FieldExpressionFactory.questionMark()).withHour(FieldExpressionFactory.on(hour)).withMinute(FieldExpressionFactory.on(minute)).withSecond(FieldExpressionFactory.on(second)).instance();
            }
            String cronAsString = cron.asString();
            log.info(cronAsString);
            return cronAsString;
        }
    }

    /**
     * @param params  参数
     * @param cronStr
     */
    public void createTaskJob(String params, String cronStr, String title, String handler) {

        // 获取 执行器id
        Integer executorId = findExecutorId();

        JobAddRequest request = new JobAddRequest();
        request.setJobGroup(executorId) // 开发环境
                .setJobDesc(title)
                .setScheduleConf(cronStr)
                .setExecutorHandler(handler)
                .setExecutorParam(params)
                .setAuthor("system");
        ReturnT result = xxlJobService.execute(request);
        System.out.println("createCheckTaskJob JobAddRequest result:" + JSON.toJSONString(result));
    }

    /**
     * @param params  参数
     * @param cronStr
     */
    public ReturnT createTaskJobResult(String params, String cronStr, String title, String handler) {

        // 获取 执行器id
        Integer executorId = findExecutorId();

        JobAddRequest request = new JobAddRequest();
        request.setJobGroup(executorId) // 开发环境
                .setJobDesc(title)
                .setScheduleConf(cronStr)
                .setExecutorHandler(handler)
                .setExecutorParam(params)
                .setAuthor("system");
        ReturnT result = xxlJobService.execute(request);
        System.out.println("createCheckTaskJob JobAddRequest result:" + JSON.toJSONString(result));
        return result;
    }

    /**
     * 获取 执行器id
     *
     * @return
     */
    public Integer findExecutorId() {
        ExecutorGetRequest getRequest = new ExecutorGetRequest();
        getRequest.setAppname(xxlJobProperties.getAppname());
        getRequest.setStart(0);
        getRequest.setLength(1);
        ReturnT executorReturn = xxlJobService.execute(getRequest);
        if (executorReturn.getContent() == null) {
            log.info("执行器配置错误！");
        }

        Integer executorId = null;
        try {
            ListGetResponse executorResponse = (ListGetResponse) (executorReturn.getContent());
            List groupVoList = executorResponse.getData();
            JSONObject jsonObject = (JSONObject) groupVoList.get(0);
            XxlJobGroupVo xxlJobGroupVo = JSONObject.toJavaObject(jsonObject, XxlJobGroupVo.class);
            executorId = xxlJobGroupVo.getId();
        } catch (Exception e) {
            e.printStackTrace();
            log.info("执行器配置错误！");
        }
        return executorId;
    }

    /**
     * 获取任务列表
     *
     * @param executorId     执行器id:  默认当前执行器的id; -1: 所有执行器
     * @param executorHandle
     */
    public List<XxlJobVo> findExecutorList(Integer executorId, String executorHandle) {
        // 获取 执行器id
        if (executorId == null) {
            executorId = findExecutorId();
        } else if (executorId == -1) {
            executorId = null;
        }

        JobListRequest jobListRequest = new JobListRequest();
        jobListRequest.setJobGroup(executorId);
        jobListRequest.setExecutorHandler(executorHandle);
        jobListRequest.setTriggerStatus(1);
        jobListRequest.setLength(999);
        jobListRequest.setStart(0);
        ReturnT executorReturn = xxlJobService.execute(jobListRequest);
        ListGetResponse<XxlJobVo> getResponse = (ListGetResponse) executorReturn.getContent();
        List<XxlJobVo> jobVo = getResponse.getData();

        return jobVo;
    }

    public static void main(String[] args) {
        FrequencyDTO frequencyDTO = new FrequencyDTO();
        frequencyDTO.setFrequencyKey("month");
        frequencyDTO.setTime("00:00:00");
        frequencyDTO.setDate("");
        frequencyDTO.setDayNum(0);
        frequencyDTO.setMonthNum(6);
        //   frequencyDTO.setAdvanceHour(-advanceHour);
        String startCronStr = generateCronBy(frequencyDTO);
        ZonedDateTime zonedDateTime = CronUtil.calculateTime("17 15 17 7 9 ? 2024", 1);
        LocalDateTime startTaskTime = zonedDateTime.toLocalDateTime();
        System.out.println(startTaskTime);
    }


    public static String generateCronBy(FrequencyDTO frequencyDTO) {
        String frequencyKey = frequencyDTO.getFrequencyKey();
        if (StrUtil.isBlank(frequencyKey)) {
            return null;
        }

        String cronStr = null;
        // 单次
        if (CheckFrequencyEnum.one.getCode().equals(frequencyKey)) {
            String date = frequencyDTO.getDate();
            String time = frequencyDTO.getTime();
            String dateTimeStr = date + "T" + time;
            LocalDateTime dateTime = LocalDateTimeUtil.parse(dateTimeStr);
            cronStr = CronUtil.generateCronByOne(dateTime);
        }

        // 每小时
        if (CheckFrequencyEnum.hour.getCode().equals(frequencyKey)) {
            Integer minute = frequencyDTO.getMinute();
            Integer second = frequencyDTO.getSecond();
            cronStr = CronUtil.generateCronByEveryHour(second, minute);
        }

        // 每日
        if (CheckFrequencyEnum.day.getCode().equals(frequencyKey)) {
            String time = frequencyDTO.getTime();
            cronStr = CronUtil.generateCronByEveryDay(time);
        }

        // 每周
        if (CheckFrequencyEnum.week.getCode().equals(frequencyKey)) {
            String time = frequencyDTO.getTime();
            Integer weekday = frequencyDTO.getDayNum();
            List<WeekdayEnum> weekdayEnumList = new ArrayList<>();
            if (weekday == 1) {
                weekdayEnumList.add(WeekdayEnum.MONDAY);
            } else if (weekday == 2) {
                weekdayEnumList.add(WeekdayEnum.TUESDAY);
            } else if (weekday == 3) {
                weekdayEnumList.add(WeekdayEnum.WEDNESDAY);
            } else if (weekday == 4) {
                weekdayEnumList.add(WeekdayEnum.THURSDAY);
            } else if (weekday == 5) {
                weekdayEnumList.add(WeekdayEnum.FRIDAY);
            } else if (weekday == 6) {
                weekdayEnumList.add(WeekdayEnum.SATURDAY);
            } else if (weekday == 7) {
                weekdayEnumList.add(WeekdayEnum.SUNDAY);
            } else {
                return null;
            }
            cronStr = CronUtil.generateCronByEveryWeek(weekdayEnumList, time);
        }

        // 每月
        if (CheckFrequencyEnum.month.getCode().equals(frequencyKey)) {
            Integer monthday = frequencyDTO.getDayNum();
            String time = frequencyDTO.getTime();
            if (monthday != 0) {
                List<Integer> monthdayList = new ArrayList<>();
                monthdayList.add(monthday);
                cronStr = CronUtil.generateCronByEveryMonth(monthdayList, time);
            } else {
                cronStr = generateCronByLastDay(null, time);
            }
        }


        // 每季
        if (CheckFrequencyEnum.quarter.getCode().equals(frequencyKey)) {
            Integer monthNum = frequencyDTO.getMonthNum();
            Integer monthday = frequencyDTO.getDayNum();
            String time = frequencyDTO.getTime();
            List<Integer> monthNumList = new ArrayList<>();
            if (monthNum == 1) { // 每季 第一个月
                monthNumList.add(1);
                monthNumList.add(4);
                monthNumList.add(7);
                monthNumList.add(10);
            } else if (monthNum == 2) { // 每季 第二个月
                monthNumList.add(2);
                monthNumList.add(5);
                monthNumList.add(8);
                monthNumList.add(11);
            } else if (monthNum == 3) { // 每季 第三个月
                monthNumList.add(3);
                monthNumList.add(6);
                monthNumList.add(9);
                monthNumList.add(12);
            } else {
                return null;
            }
            monthNumList.add(monthNum);

            if (monthday != 0) {
                List<Integer> monthdayList = new ArrayList<>();
                monthdayList.add(monthday);
                cronStr = CronUtil.generateCronByEveryYear(monthNumList, monthdayList, time);
            } else {
                cronStr = CronUtil.generateCronByLastDay(monthNumList, time);
            }
        }

        // 每年
        if (CheckFrequencyEnum.year.getCode().equals(frequencyKey)) {
            Integer monthNum = frequencyDTO.getMonthNum();
            Integer monthday = frequencyDTO.getDayNum();
            String time = frequencyDTO.getTime();

            List<Integer> monthNumList = new ArrayList<>();
            monthNumList.add(monthNum);
            if (monthday != 0) {
                List<Integer> monthdayList = new ArrayList<>();
                monthdayList.add(monthday);
                cronStr = CronUtil.generateCronByEveryYear(monthNumList, monthdayList,time);
            } else {
                cronStr = CronUtil.generateCronByLastDay(monthNumList, time);
            }

        }
        return cronStr;
    }
}
