package com.xmomen.module.schedule.controller;

import com.xmomen.module.schedule.QuartzManager;
import com.xmomen.module.schedule.controller.vo.AddQuartzJob;
import com.xmomen.module.schedule.controller.vo.ScheduleJobVo;
import com.xmomen.module.schedule.controller.vo.UpdateQuartzJob;
import com.xmomen.module.schedule.service.ScheduleJobService;
import com.xmomen.module.schedule.entity.ScheduleJob;
import com.xmomen.framework.mybatis.page.Page;
import com.xmomen.framework.support.SpringContextUtil;
import com.xmomen.framework.web.exceptions.ArgumentValidException;
import org.quartz.Job;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 定时任务控制器类，用于处理与定时任务相关的 HTTP 请求。
 * Created by Jeng on 2016/2/23.
 */
@RestController
public class ScheduleController {

    // 定义一个静态的List，用于存储AddQuartzJob对象。
    // 这里使用静态List可能存在线程安全问题，在多线程环境下需要注意数据的一致性。
    public static List<AddQuartzJob> data = new ArrayList<AddQuartzJob>();

    // 自动注入定时任务服务类，用于处理定时任务的业务逻辑
    @Autowired
    ScheduleJobService scheduleJobService;

    /**
     * 新增定时任务的处理方法。
     *
     * @param addQuartzJob 包含新增定时任务信息的对象
     * @param bindingResult 用于验证参数的结果对象
     * @throws ArgumentValidException 如果参数验证失败，抛出此异常
     */
    @RequestMapping(value = "/schedule", method = RequestMethod.POST)
    public void addQuartzJob(@RequestBody @Valid AddQuartzJob addQuartzJob, BindingResult bindingResult) throws ArgumentValidException {
        // 验证参数是否合法，如果有错误则抛出参数验证异常
        if (bindingResult != null && bindingResult.hasErrors()) {
            throw new ArgumentValidException(bindingResult);
        }
        // 获取触发器ID
        String triggerId = addQuartzJob.getJobTriggerId();
        // 判断Spring容器中是否存在该触发器，如果不存在则抛出非法参数异常
        if (!SpringContextUtil.getApplicationContext().containsBean(triggerId)) {
            throw new IllegalArgumentException("所选模板文件错误，此模板不属于Job接口实现类");
        }
        // 从Spring容器中获取触发器对象
        Object obj = SpringContextUtil.getApplicationContext().getBean(triggerId);
        if (obj == null) {
            throw new IllegalArgumentException("所选模板文件错误，此模板不属于Job接口实现类");
        }
        // 判断触发器对象是否为Job接口的实现类，如果不是则抛出非法参数异常
        if (obj instanceof Job) {
            Job job = (Job) obj;
            try {
                // 创建ScheduleJob对象，并设置相关属性
                ScheduleJob scheduleJob = new ScheduleJob();
                scheduleJob.setJobName(addQuartzJob.getJobName());
                scheduleJob.setJobGroup(addQuartzJob.getJobGroup());
                scheduleJob.setCronExpression(addQuartzJob.getCronExpression());
                scheduleJob.setJobDescription(addQuartzJob.getDescription());
                scheduleJob.setTriggerId(addQuartzJob.getJobTriggerId());
                // 根据任务是否启动设置任务状态
                scheduleJob.setJobStatus(addQuartzJob.getStarted()? Trigger.STATE_NORMAL : Trigger.STATE_PAUSED);
                // 调用定时任务服务类的方法添加定时任务到数据库
                scheduleJobService.addScheduleJob(scheduleJob);
                // 调用QuartzManager的方法添加Quartz任务
                QuartzManager.addJob(addQuartzJob.getJobName(), addQuartzJob.getJobGroup(), job.getClass(), addQuartzJob.getCronExpression());
                // 如果任务状态为暂停，则调用QuartzManager的方法暂停任务
                if (Trigger.STATE_PAUSED == scheduleJob.getJobStatus()) {
                    QuartzManager.pauseJob(addQuartzJob.getJobName(), addQuartzJob.getJobGroup());
                }
            } catch (SchedulerException e) {
                e.printStackTrace();
            } catch (ParseException e) {
                throw new IllegalArgumentException("错误的cron表达式");
            }
        } else {
            throw new IllegalArgumentException("所选模板文件错误，此模板不属于Job接口实现类");
        }
    }

    /**
     * 获取定时任务列表的处理方法。
     *
     * @param keyword 搜索关键词（可选）
     * @param limit 每页显示的记录数
     * @param offset 页码
     * @return 包含定时任务信息的分页对象
     */
    @RequestMapping(value = "/schedule", method = RequestMethod.GET)
    public Page<ScheduleJobVo> getQuartzJob(@RequestParam(value = "keyword", required = false) String keyword,
                                            @RequestParam(value = "limit") Integer limit,
                                            @RequestParam(value = "offset") Integer offset) {
        // 调用定时任务服务类的方法查询定时任务列表
        return scheduleJobService.queryScheduleJobs(keyword, limit, offset);
    }

    /**
     * 修改定时任务的处理方法。
     *
     * @param id 要修改的定时任务的ID
     * @param updateQuartzJob 包含更新后定时任务信息的对象
     * @param bindingResult 用于验证参数的结果对象
     * @throws ArgumentValidException 如果参数验证失败，抛出此异常
     */
    @RequestMapping(value = "/schedule/{id}", method = RequestMethod.PUT)
    public void updateQuartzJob(@PathVariable(value = "id") Integer id,
                                @RequestBody @Valid UpdateQuartzJob updateQuartzJob, BindingResult bindingResult) throws ArgumentValidException {
        // 验证参数是否合法，如果有错误则抛出参数验证异常
        if (bindingResult != null && bindingResult.hasErrors()) {
            throw new ArgumentValidException(bindingResult);
        }
        // 调用定时任务服务类的方法更新定时任务
        scheduleJobService.updateScheduleJob(id, updateQuartzJob);
    }

    /**
     * 获取定时任务模板的处理方法。
     *
     * @return 包含定时任务模板信息的列表
     */
    @RequestMapping(value = "/schedule/template", method = RequestMethod.GET)
    public List<Map<String, String>> getQuartzTemplate() {
        // 从Spring容器中获取所有Job类型的Bean
        Map<String, Job> jobs = SpringContextUtil.getApplicationContext().getBeansOfType(Job.class);
        List<Map<String, String>> strings = new ArrayList<Map<String, String>>();
        // 遍历所有Job类型的Bean，构建包含触发器名称和键的Map，并添加到列表中
        for (Map.Entry<String, Job> stringJobEntry : jobs.entrySet()) {
            Map<String, String> stringMap = new HashMap<String, String>();
            stringMap.put("triggerName", stringJobEntry.getValue().getClass().getName());
            stringMap.put("triggerKey", stringJobEntry.getKey());
            strings.add(stringMap);
        }
        return strings;
    }

    /**
     * 删除定时任务的处理方法。
     *
     * @param id 要删除的定时任务的ID
     */
    @RequestMapping(value = "/schedule/{id}", method = RequestMethod.DELETE)
    public void deleteQuartzJob(@PathVariable(value = "id") Integer id) {
        // 调用定时任务服务类的方法删除定时任务
        scheduleJobService.deleteScheduleJob(id);
    }
}