package tech.easyflow.job.service.impl;

import com.mybatisflex.spring.service.impl.ServiceImpl;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import tech.easyflow.common.constant.enums.EnumMisfirePolicy;
import tech.easyflow.common.constant.enums.EnumJobStatus;
import tech.easyflow.common.cache.RedisLockExecutor;
import tech.easyflow.job.entity.SysJob;
import tech.easyflow.job.job.JobConstant;
import tech.easyflow.job.job.QuartzJob;
import tech.easyflow.job.job.QuartzJobNoConcurrent;
import tech.easyflow.job.mapper.SysJobMapper;
import tech.easyflow.job.service.SysJobService;
import tech.easyflow.job.util.JobUtil;

import javax.annotation.Resource;
import java.io.Serializable;
import java.math.BigInteger;
import java.time.Duration;
import java.util.Collection;
import java.util.Collections;

/**
 * 系统任务表 服务层实现。
 *
 * @author xiaoma
 * @since 2025-05-20
 */
@Service
public class SysJobServiceImpl extends ServiceImpl<SysJobMapper, SysJob>  implements SysJobService {

    private static final String JOB_LOCK_KEY_PREFIX = "easyflow:lock:job:";
    private static final Duration LOCK_WAIT_TIMEOUT = Duration.ofSeconds(2);
    private static final Duration LOCK_LEASE_TIMEOUT = Duration.ofSeconds(10);

    protected Logger log = LoggerFactory.getLogger(SysJobServiceImpl.class);

    @Resource
    private Scheduler scheduler;

    @Resource
    private RedisLockExecutor redisLockExecutor;

    @Override
    public void test() {
        System.out.println("java bean 动态执行");
    }

    @Override
    public void testParam(String a, Boolean b, Integer c) {
        System.out.println("动态执行spring bean，执行参数：" + "a="+ a + ",b="+ b + ",c="+ c);
    }

    @Override
    public void addJob(SysJob job) {
        Integer allowConcurrent = job.getAllowConcurrent();
        Class<? extends Job> jobClass = allowConcurrent  == 1 ? QuartzJob.class : QuartzJobNoConcurrent.class;

        JobDetail jobDetail = JobBuilder.newJob(jobClass)
                .withIdentity(JobUtil.getJobKey(job))
                .build();

        jobDetail.getJobDataMap().put(JobConstant.JOB_MAP_BEAN_NAME, job);

        CronScheduleBuilder cron = CronScheduleBuilder.cronSchedule(job.getCronExpression());

        Integer misfirePolicy = job.getMisfirePolicy();
        if (EnumMisfirePolicy.MISFIRE_DO_NOTHING.getCode() == misfirePolicy) {
            cron.withMisfireHandlingInstructionDoNothing();
        }
        if (EnumMisfirePolicy.MISFIRE_FIRE_AND_PROCEED.getCode() == misfirePolicy) {
            cron.withMisfireHandlingInstructionFireAndProceed();
        }
        if (EnumMisfirePolicy.MISFIRE_IGNORE_MISFIRES.getCode() == misfirePolicy) {
            cron.withMisfireHandlingInstructionIgnoreMisfires();
        }

        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(JobUtil.getTriggerKey(job))
                .withSchedule(cron).build();

        try {
            scheduler.scheduleJob(jobDetail,trigger);
        } catch (SchedulerException e) {
            log.error("启动任务失败：", e);
            throw new RuntimeException(e);
        }
    }

    @Override
    public void deleteJob(Collection<Serializable> ids) {
        try {
            for (Serializable id : ids) {
                SysJob sysJob = new SysJob();
                sysJob.setId(new BigInteger(id.toString()));
                scheduler.deleteJob(JobUtil.getJobKey(sysJob));
            }
        } catch (SchedulerException e) {
            log.error("删除任务失败：", e);
            throw new RuntimeException(e);
        }
    }

    @Override
    public void startJob(BigInteger id) {
        redisLockExecutor.executeWithLock(JOB_LOCK_KEY_PREFIX + id, LOCK_WAIT_TIMEOUT, LOCK_LEASE_TIMEOUT, () -> {
            SysJob sysJob = this.getById(id);
            if (sysJob == null) {
                throw new IllegalStateException("任务不存在，id=" + id);
            }
            try {
                JobKey jobKey = JobUtil.getJobKey(sysJob);
                if (!scheduler.checkExists(jobKey)) {
                    addJob(sysJob);
                }
                if (!Integer.valueOf(EnumJobStatus.RUNNING.getCode()).equals(sysJob.getStatus())) {
                    SysJob update = new SysJob();
                    update.setId(id);
                    update.setStatus(EnumJobStatus.RUNNING.getCode());
                    this.updateById(update);
                }
            } catch (SchedulerException e) {
                log.error("启动任务失败：id={}", id, e);
                throw new RuntimeException(e);
            }
        });
    }

    @Override
    public void stopJob(BigInteger id) {
        redisLockExecutor.executeWithLock(JOB_LOCK_KEY_PREFIX + id, LOCK_WAIT_TIMEOUT, LOCK_LEASE_TIMEOUT, () -> {
            SysJob sysJob = this.getById(id);
            if (sysJob == null) {
                throw new IllegalStateException("任务不存在，id=" + id);
            }
            try {
                JobKey jobKey = JobUtil.getJobKey(sysJob);
                if (scheduler.checkExists(jobKey)) {
                    deleteJob(Collections.singletonList(id));
                }
                if (!Integer.valueOf(EnumJobStatus.STOP.getCode()).equals(sysJob.getStatus())) {
                    SysJob update = new SysJob();
                    update.setId(id);
                    update.setStatus(EnumJobStatus.STOP.getCode());
                    this.updateById(update);
                }
            } catch (SchedulerException e) {
                log.error("停止任务失败：id={}", id, e);
                throw new RuntimeException(e);
            }
        });
    }
}
