package com.njzscloud.common.sichen.util;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.njzscloud.common.core.ex.Exceptions;
import com.njzscloud.common.sichen.contant.ScheduleType;
import com.njzscloud.common.sichen.executor.SichenExecutor;
import com.njzscloud.common.sichen.service.CombineStoreService;
import com.njzscloud.common.sichen.support.CronExpression;
import com.njzscloud.common.sichen.support.TaskInfo;
import lombok.extern.slf4j.Slf4j;

import java.text.ParseException;
import java.util.Date;
import java.util.List;

@Slf4j
public final class TaskUtil {
    private static final CombineStoreService COMBINE_STORE_SERVICE = SpringUtil.getBean(CombineStoreService.class);
    private final static SichenExecutor SICHEN_EXECUTOR = SpringUtil.getBean(SichenExecutor.class);

    /**
     * 计算下次执行时间
     *
     * @param now      当前时间（秒）
     * @param taskInfo 任务
     */
    public static long computedNextTiming(long now, TaskInfo taskInfo) {
        return computedNextTiming(now, taskInfo.getScheduleType(), taskInfo.getScheduleConf());
    }

    /**
     * 计算下次执行时间
     *
     * @param taskInfo 任务
     */
    public static long computedNextTiming(TaskInfo taskInfo) {
        return computedNextTiming(System.currentTimeMillis() / 1000, taskInfo.getScheduleType(), taskInfo.getScheduleConf());
    }

    /**
     * 计算下次执行时间
     *
     * @param scheduleType 调度类型
     * @param scheduleConf 调度配置
     */
    public static long computedNextTiming(ScheduleType scheduleType, String scheduleConf) {
        return computedNextTiming(System.currentTimeMillis() / 1000, scheduleType, scheduleConf);
    }

    /**
     * 计算下次执行时间
     *
     * @param now          当前时间（秒）
     * @param scheduleType 调度类型
     * @param scheduleConf 调度配置
     */
    public static long computedNextTiming(long now, ScheduleType scheduleType, String scheduleConf) {
        switch (scheduleType) {
            case Fixed:
                return now + Long.parseLong(scheduleConf);
            case Cron:
                try {
                    return new CronExpression(scheduleConf)
                        .getNextValidTimeAfter(new Date(now * 1000))
                        .getTime() / 1000;
                } catch (ParseException e) {
                    log.error("任务调度表达式解析错误", e);
                    return 0;
                }
            case Manually:
                return 0;
            default:
                throw Exceptions.error("调度类型错误：{}", scheduleType);
        }
    }

    /**
     * 触发一次
     *
     * @param id 任务 Id
     */
    public static boolean trigger(Long id) {
        return COMBINE_STORE_SERVICE.trigger(id);
    }

    /**
     * 注册任务（优先写入数据库）
     *
     * @param taskInfo 任务
     */
    public static void registerTask(TaskInfo taskInfo) {
        Assert.notBlank(taskInfo.getTaskName(), () -> Exceptions.exception("任务名称不能为空"));
        Assert.notBlank(taskInfo.getFn(), () -> Exceptions.exception("任务执行函数不能为空"));
        boolean scheduleType = taskInfo.getScheduleType() != null;
        Assert.isTrue(scheduleType, () -> Exceptions.exception("调度方式不能为空"));
        Assert.isTrue(taskInfo.getScheduleType() == ScheduleType.Manually ? StrUtil.isBlank(taskInfo.getScheduleConf()) : StrUtil.isNotBlank(taskInfo.getScheduleConf()), () -> Exceptions.exception("调度方式或调度配置错误"));
        COMBINE_STORE_SERVICE.registerTask(taskInfo);
    }

    /**
     * 注册任务
     *
     * @param taskInfo 任务
     */
    public static void registerMemTask(TaskInfo taskInfo) {
        Assert.notBlank(taskInfo.getTaskName(), () -> Exceptions.exception("任务名称不能为空"));
        Assert.notBlank(taskInfo.getFn(), () -> Exceptions.exception("任务执行函数不能为空"));
        boolean scheduleType = taskInfo.getScheduleType() != null;
        Assert.isTrue(scheduleType, () -> Exceptions.exception("调度方式不能为空"));
        Assert.isTrue(taskInfo.getScheduleType() == ScheduleType.Manually ? StrUtil.isBlank(taskInfo.getScheduleConf()) : StrUtil.isNotBlank(taskInfo.getScheduleConf()), () -> Exceptions.exception("调度方式或调度配置错误"));
        COMBINE_STORE_SERVICE.memoryTaskStoreService.registerTask(taskInfo);
    }

    /**
     * 执行任务
     *
     * @param task 任务
     */
    public static void execute(TaskInfo task) {
        SICHEN_EXECUTOR.execute(task, false);
    }

    /**
     * 执行任务
     *
     * @param task 任务
     */
    public static void execute(TaskInfo task, boolean manually) {
        SICHEN_EXECUTOR.execute(task, manually);
    }

    /**
     * 执行任务
     *
     * @param tasks 任务
     */
    public static void execute(List<TaskInfo> tasks) {
        SICHEN_EXECUTOR.execute(tasks, false);
    }

    /**
     * 执行任务
     *
     * @param tasks 任务
     */
    public static void execute(List<TaskInfo> tasks, boolean manually) {
        SICHEN_EXECUTOR.execute(tasks, manually);
    }
}
