package com.ruoyi.web.controller.tool;

import cn.hutool.core.util.StrUtil;
import com.mybatisflex.core.paginate.Page;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.enums.DictEnum;
import com.ruoyi.common.utils.ExcelUtil;
import com.ruoyi.common.web.controller.BaseController;
import com.ruoyi.common.web.domain.PageData;
import com.ruoyi.framework.annotation.RyLog;
import com.ruoyi.schedule.domain.JobTriggers;
import com.ruoyi.schedule.domain.SysJob;
import org.noear.solon.annotation.*;
import org.noear.solon.auth.annotation.AuthPermissions;
import org.noear.solon.core.handle.Result;
import org.noear.solon.scheduling.annotation.Scheduled;
import org.noear.solon.scheduling.scheduled.JobHolder;
import org.noear.solon.scheduling.scheduled.manager.IJobManager;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 定时任务 操作处理
 * @author ruoyi
 */
@Controller
@Mapping("tool/job")
public class JobController extends BaseController {

    @Inject
    IJobManager jobManager;

    @Inject
    Scheduler scheduler;

    /**
     * 查询定时任务列表
     */
    @AuthPermissions("tool:job:list")
    @Get
    @Mapping("list")
    public PageData<SysJob> list(Page<SysJob> page, SysJob sysJob) {
        List<SysJob> sysJobList = getList(sysJob);
        // 分页
        List<SysJob> list = sysJobList.stream()
                .skip((page.getPageNumber() - 1) * page.getPageSize())
                .limit(page.getPageSize())
                .collect(Collectors.toList());
        return getPageData(list).total(sysJobList.size());
    }

    /**
     * 导出定时任务列表
     */
    @RyLog(title = "定时任务", businessType = BusinessType.EXPORT)
    @AuthPermissions("tool:job:export")
    @Post
    @Mapping("export")
    public void export(SysJob sysJob) {
        List<SysJob> sysJobList = getList(sysJob);
        ExcelUtil.export(sysJobList);
    }

    /**
     * 查询定时任务详情
     */
    @AuthPermissions("tool:job:query")
    @Get
    @Mapping("{jobName}")
    public SysJob info(@Path String jobName) {
        JobHolder jobHolder = jobManager.jobGet(jobName);
        List<JobTriggers> jobTriggersList = getJobTriggers();
        return toSysJob(jobHolder, jobTriggersList);
    }

    /**
     * 状态修改
     */
    @RyLog(title = "定时任务", businessType = BusinessType.UPDATE)
    @AuthPermissions("tool:job:changeStatus")
    @Put
    @Mapping("changeStatus")
    public Result<Void> changeStatus(@Body SysJob sysJob) {
        if(!jobManager.jobExists(sysJob.getJobName())) {
            return Result.failure("任务不存在!");
        }
        JobHolder jobHolder = jobManager.jobGet(sysJob.getJobName());
        if(DictEnum.SYS_JOB_STATUS.OK.getValue().equals(sysJob.getStatus())) {
            jobManager.jobStart(sysJob.getJobName(), null);
        } else {
            jobManager.jobStop(sysJob.getJobName());
        }
        return Result.succeed();
    }

    /**
     * 删除定时任务
     */
    @RyLog(title = "定时任务", businessType = BusinessType.DELETE)
    @AuthPermissions("tool:job:remove")
    @Delete
    @Mapping("{jobNames}")
    public Result<Void> delete(@Path String[] jobNames) {
        for (String jobName : jobNames) {
            jobManager.jobRemove(jobName);
        }
        return Result.succeed();
    }

    private List<SysJob> getList(SysJob sysJob) {
        Map<String, JobHolder> jobHolderMap = jobManager.jobGetAll();
        List<SysJob> sysJobs = new ArrayList<>();
        List<JobTriggers> jobTriggersList = getJobTriggers();
        for (Map.Entry<String, JobHolder> entry : jobHolderMap.entrySet()) {
            sysJobs.add(toSysJob(entry.getValue(), jobTriggersList));
        }
        // 根据查询条件检索
        return sysJobs.stream()
                .filter(job -> StrUtil.isEmpty(sysJob.getJobName()) || job.getJobName().equals(sysJob.getJobName()))
                .filter(job -> StrUtil.isEmpty(sysJob.getJobSimpleName()) || job.getJobSimpleName().equals(sysJob.getJobSimpleName()))
                .filter(job -> StrUtil.isEmpty(sysJob.getStatus()) || job.getStatus().equals(sysJob.getStatus()))
                .collect(Collectors.toList());
    }

    private SysJob toSysJob(JobHolder jobHolder, List<JobTriggers> jobTriggersList) {
        Scheduled scheduled = jobHolder.getScheduled();
        SysJob sysJob = new SysJob();
        sysJob.setJobName(jobHolder.getName());
        sysJob.setJobSimpleName(jobHolder.getSimpleName());
        sysJob.setCronExpression(StrUtil.isNotEmpty(scheduled.cron()) ? scheduled.cron() : String.valueOf(scheduled.fixedRate()));
        sysJob.setStatus(DictEnum.SYS_JOB_STATUS.PAUSE.getValue());
        // 匹配当前 Job  TODO 按照名称 + 分组匹配
        Optional<JobTriggers> optionalJobTriggers = jobTriggersList.stream().filter(jobTriggers -> jobHolder.getName().equals(jobTriggers.getJobKey().getName())).findFirst();
        if(optionalJobTriggers.isPresent()) {
            JobTriggers jobTriggers = optionalJobTriggers.get();
            sysJob.setJobGroup(jobTriggers.getJobKey().getGroup());
            List<JobTriggers.TriggerOfJob> triggersOfJob = jobTriggers.getTriggersOfJob();
            if(!triggersOfJob.isEmpty()) {
                // Job和触发器 Trigger目前是一对一
                JobTriggers.TriggerOfJob triggerOfJob = triggersOfJob.get(0);
                if(triggerOfJob.getTriggerState() == Trigger.TriggerState.NORMAL) {
                    sysJob.setStatus(DictEnum.SYS_JOB_STATUS.OK.getValue());
                }
                Trigger trigger = triggerOfJob.getTrigger();
                sysJob.setStartTime(trigger.getStartTime());
                sysJob.setEndTime(trigger.getEndTime());
                sysJob.setNextFireTime(trigger.getNextFireTime());
                sysJob.setPreviousFireTime(trigger.getPreviousFireTime());
            }
        }
        return sysJob;
    }

    private List<JobTriggers> getJobTriggers() {
        List<JobTriggers> list = new ArrayList<>();
        try {
            // 查询所有的 JobKey
            Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.anyJobGroup());
            if(!jobKeys.isEmpty()) {
                for (JobKey jobKey : jobKeys) {
                    JobTriggers jobTriggers = new JobTriggers();
                    jobTriggers.setJobKey(jobKey);
                    // 查询当前 Job的触发器（也就是 Trigger。同一个 Job可以有多个 Trigger）
                    List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
                    List<JobTriggers.TriggerOfJob> triggersOfJob = new ArrayList<>();
                    for (Trigger trigger : triggers) {
                        JobTriggers.TriggerOfJob triggerOfJob = jobTriggers.new TriggerOfJob();
                        // 查询触发器状态
                        Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
                        triggerOfJob.setTrigger(trigger);
                        triggerOfJob.setTriggerState(triggerState);
                        triggersOfJob.add(triggerOfJob);
                    }
                    jobTriggers.setTriggersOfJob(triggersOfJob);
                    list.add(jobTriggers);
                }
            }
        } catch (SchedulerException ignored) {
        }
        return list;
    }

}
