package cn.iocoder.yudao.module.system.job.robot;

import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.module.system.enums.redis.RobotCacheLockEnum;
import cn.iocoder.yudao.module.system.service.robot.RobotInformationService;
import cn.iocoder.yudao.module.system.service.robot.job.AutoChargeService;
import cn.iocoder.yudao.module.system.service.robot.job.CycleService;
import cn.iocoder.yudao.module.system.service.robot.job.DistributeTasksService;
import cn.iocoder.yudao.module.system.service.robot.job.InitTaskService;
import cn.iocoder.yudao.module.system.service.robot.job.RobotTaskAutoMoveService;
import cn.iocoder.yudao.module.system.service.robot.pathplanning.RobotPathPlanningService;
import cn.iocoder.yudao.module.system.service.statistics.RobotWorkingHoursStatisticsService;
import cn.iocoder.yudao.module.system.util.redis.RedissonUtils;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

import java.util.HashSet;
import java.util.Set;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.REDISSON_NOT_OBTAIN_LOCK;


@Component
@Slf4j
public class RobotJob {

    @Resource
    private RedissonUtils redissonUtils;

    @Autowired
    private DistributeTasksService distributeTasksService;

    @Autowired
    private RobotTaskAutoMoveService robotTaskAutoMoveService;

    @Autowired
    private AutoChargeService autoChargeService;

    @Autowired
    private CycleService cycleService;

    @Autowired
    private RobotPathPlanningService robotPathPlanningService;

    @Resource
    private RobotInformationService informationService;

    @Resource
    private InitTaskService initTaskService;

    @Resource
    private RobotWorkingHoursStatisticsService robotWorkingHoursStatisticsService;


    //下发自动移库任务--- 废弃---产品不要自动移库
//    @XxlJob("DistributeAutoMoveJob")
    @TenantJob
    public void distributeAutoMoveJob() throws InterruptedException {
        log.info("----下发自动移库任务----");
        Set<String> locks = new HashSet<>();
        locks.add(RobotCacheLockEnum.ROBOT_TASK_DISTRIBUTE_LOCK.getKey());
        locks.add(RobotCacheLockEnum.ROBOT_TASK_ADD_LOCK.getKey());
        RLock lock = redissonUtils.getLocks(locks);
        if (lock.tryLock()) {
            try {
                robotTaskAutoMoveService.distributeAutoMoveJob();
            } finally {
                lock.unlock();
            }
        } else {
            log.info("下发自动移库任务未获取到锁");
            throw exception(REDISSON_NOT_OBTAIN_LOCK);
        }
    }

    //下发自动充电任务
    @XxlJob("AutoChargeJob")
    @TenantJob
    public void AutoChargeJob() {

        RLock lock = redissonUtils.getLock(RobotCacheLockEnum.ROBOT_TASK_DISTRIBUTE_LOCK.getKey());
        if (lock.tryLock()) {
            try {
                log.info("----111111下发自动充电任务----");
                autoChargeService.autoChargeJob();
            } catch (Exception e) {
                log.info("自动充电异常 :{}", e);
            } finally {
                lock.unlock();
            }
        } else {
            log.info("下发自动充电任务未获取到锁");
            throw exception(REDISSON_NOT_OBTAIN_LOCK);
        }
    }

    /**
     * 下发任务给路径规划
     */
    @XxlJob("DistributeTasksToPathPlanningJob")
    @TenantJob
    public void DistributeTasksToPathPlanningJob() {

        RLock lock = redissonUtils.getLock(RobotCacheLockEnum.ROBOT_TASK_DISTRIBUTE_LOCK.getKey());
        if (lock.tryLock()) {
            try {
                log.info("----111111下发任务给路径规划----");
                robotPathPlanningService.sendTaskToPP();
            } catch (Exception e) {
                log.info("----分配任务异常---- :{}", e);
            } finally {
                lock.unlock();
            }
        } else {
            log.info("下发任务给路径规划未获取到锁");
            throw exception(REDISSON_NOT_OBTAIN_LOCK);
        }
    }


    /**
     * 创建循环任务
     */
    @XxlJob("CycleTaskJob")
    @TenantJob
    public void cycleTaskJob() {

        RLock lock = redissonUtils.getLock(RobotCacheLockEnum.ROBOT_TASK_ADD_LOCK.getKey());
        if (lock.tryLock()) {

            try {
                log.info("----111111创建循环任务----");
                cycleService.cycleTaskJob();
            } catch (Exception e) {
                log.error("创建循环任务异常 :{}", e);
            } finally {
                lock.unlock();
            }

        } else {
            log.info("下发任务给路径规划未获取到锁");
            throw exception(REDISSON_NOT_OBTAIN_LOCK);
        }
    }


    /**
     * 维护车机心跳(废弃  目前车机没这功能)
     */
//    @XxlJob("RcsHeartBeat")
    @TenantJob
    public void rcsHeartBeat() {

        RLock lock = redissonUtils.getLock(RobotCacheLockEnum.ROBOT_RCS_HEART_BEAT_LOCK.getKey());
        if (lock.tryLock()) {
            try {
                log.info("----维护车机心跳----");
                TenantContextHolder.setTenantId(1L);
                informationService.rcsHeartBeat();
            } finally {
                lock.unlock();
            }
        } else {
            throw exception(REDISSON_NOT_OBTAIN_LOCK);
        }
    }

    /**
     * 统计车辆工作时长
     */
    @XxlJob("StatisticsDurationJob")
    @TenantJob
    public void statisticsDuration() {
        RLock lock = redissonUtils.getLock(RobotCacheLockEnum.ROBOT_STATISTICS_DURATION_LOCK.getKey());
        if (lock.tryLock()) {
            try {
                log.info("----统计时长开始----");
                TenantContextHolder.setTenantId(1L);
                robotWorkingHoursStatisticsService.statisticsRobotDuration();
            } catch (Exception e) {
                log.info("统计工作时长异常 :{}", e);
            } finally {
                lock.unlock();
            }
        } else {
            throw exception(REDISSON_NOT_OBTAIN_LOCK);
        }
    }


    /**
     * 恢复数据 (只能是测试的时候用，上线禁止使用)
     */
    @XxlJob("initTaskJob")
    @TenantJob
    public void initTaskJob() {
        TenantContextHolder.setTenantId(1L);
        initTaskService.initTask();
    }
}
