package com.njcn.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.common.pojo.enums.common.DataStateEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.system.enums.SystemResponseEnum;
import com.njcn.system.mapper.TimersMapper;
import com.njcn.system.pojo.enums.TimerJobStatusEnum;
import com.njcn.system.pojo.param.TimersParam;
import com.njcn.system.pojo.po.Timers;
import com.njcn.system.pojo.vo.TimersVO;
import com.njcn.system.service.ITimersService;
import com.njcn.system.timer.TimerExeService;
import com.njcn.system.timer.TimerTaskRunner;
import com.njcn.web.factory.PageFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 定时任务 服务实现类
 * </p>
 *
 * @author hongawen
 * @since 2023-12-05
 */
@Service
@RequiredArgsConstructor
public class TimersServiceImpl extends ServiceImpl<TimersMapper, Timers> implements ITimersService {

    private final TimerExeService timerExeService;

    @Value("${runTake.maxRetryCount}")
    private Integer maxRetryCount;

    @Value("${runTake.delayTime}")
    private Integer delayTime;

    @Override
    public Page<TimersVO> listTimer(TimersParam queryParam) {
        QueryWrapper<TimersVO> queryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotNull(queryParam)) {
            //查询参数不为空，进行条件填充
            if (StrUtil.isNotBlank(queryParam.getSearchValue())) {
                //定时任务，待提供名称、编码模糊查询 todo...
                queryWrapper.like("timer_name", queryParam.getSearchValue());
            }
        }
        if (!Objects.isNull(queryParam.getSearchState())){
            queryWrapper.eq("job_status", queryParam.getSearchState());
        }
        queryWrapper.orderBy(true, true, "sys_timers.sort");
        queryWrapper.ne("sys_timers.state", DataStateEnum.DELETED.getCode());
        //初始化分页数据
        return this.baseMapper.page(new Page<>(PageFactory.getPageNum(queryParam), PageFactory.getPageSize(queryParam)), queryWrapper);
    }

    @Override
    public boolean addTimer(TimersParam timersParam) {
        Timers timers = new Timers();
        BeanUtil.copyProperties(timersParam, timers);
        //默认为正常状态
        timers.setState(DataStateEnum.ENABLE.getCode());
        return this.save(timers);
    }

    @Override
    public boolean editTimer(TimersParam timersParam) {
        Timers timers = new Timers();
        BeanUtil.copyProperties(timersParam, timers);
        timers.setJobStatus(TimerJobStatusEnum.STOP.getCode());
        return this.updateById(timers);
    }

    @Override
    public boolean deleteTimers(List<String> ids) {
        return this.lambdaUpdate()
                .set(Timers::getState, DataStateEnum.DELETED.getCode())
                .in(Timers::getId, ids)
                .update();
    }

    @Override
    public List<String> getActionClasses() {
        Map<String, TimerTaskRunner> timerTaskRunnerMap = SpringUtil.getBeansOfType(TimerTaskRunner.class);
        if (ObjectUtil.isNotEmpty(timerTaskRunnerMap)) {
            Collection<TimerTaskRunner> values = timerTaskRunnerMap.values();
            return values.stream().map(i -> i.getClass().getName()).collect(Collectors.toList());
        } else {
            return CollectionUtil.newArrayList();
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void start(String id) {
        // 更新库中的状态
        LambdaUpdateWrapper<Timers> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(Timers::getJobStatus, TimerJobStatusEnum.RUNNING.getCode())
                .eq(Timers::getId, id);
        this.update(wrapper);

        // 添加定时任务调度
        Timers sysTimers = this.queryTimers(id);
        timerExeService.startTimer(sysTimers.getId(), sysTimers.getCron(), sysTimers.getActionClass());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void stop(String id) {
        // 更新库中的状态
        LambdaUpdateWrapper<Timers> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(Timers::getJobStatus, TimerJobStatusEnum.STOP.getCode())
                .eq(Timers::getId, id);
        this.update(wrapper);
        // 关闭定时任务调度
        Timers sysTimers = this.queryTimers(id);
        timerExeService.stopTimer(sysTimers.getId());
    }

    @Override
    public void run(String id,String date) throws InterruptedException {
        Timers sysTimers = this.queryTimers(id);
        String actionClass = sysTimers.getActionClass();
        TimerTaskRunner timerTaskRunner;
        try {
            timerTaskRunner = (TimerTaskRunner) SpringUtil.getBean(Class.forName(actionClass));
        } catch (ClassNotFoundException e) {
            throw new BusinessException(SystemResponseEnum.TIMER_NO_CLASS);
        }
        runTaskWithRetryAndDelay(timerTaskRunner,date);
    }

    /**
     * 获取定时任务
     *
     * @author hongawen
     * @date 2020/6/30 18:26
     */
    private Timers queryTimers(String id) {
        Timers timers = this.getById(id);
        if (ObjectUtil.isEmpty(timers)) {
            throw new BusinessException(SystemResponseEnum.NOT_EXISTED);
        }
        return timers;
    }

    public void runTaskWithRetryAndDelay(TimerTaskRunner timerTaskRunner,String date) throws InterruptedException {
        // 重试次数计数器
        int retryCount = 0;
        while (retryCount < maxRetryCount) {
            try {
                System.out.println(LocalDateTime.now()+"手动重试机制："+(retryCount+1));
                timerTaskRunner.action(date);
                System.out.println("成功重试机制："+(retryCount+1));
                return; // 任务执行成功，跳出循环
            } catch (Exception e) {
                // 处理异常
                // 增加重试次数
                retryCount++;
                // 等待一段时间
                Thread.sleep(delayTime);
            }
        }
    }

}
