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

import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.system.config.poperties.ZnConfigConstant;
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.RobotTaskDetailAddVO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotTaskDO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotTaskDetailDO;
import cn.iocoder.yudao.module.system.dal.mysql.cycle.TaskCycleMapper;
import cn.iocoder.yudao.module.system.dal.mysql.houselocation.WareHouseLocationMapper;
import cn.iocoder.yudao.module.system.dal.mysql.robot.RobotTaskDetailMapper;
import cn.iocoder.yudao.module.system.dal.mysql.robot.RobotTaskMapper;
import cn.iocoder.yudao.module.system.enums.redis.RobotCacheLockEnum;
import cn.iocoder.yudao.module.system.enums.robot.LocationLockEnum;
import cn.iocoder.yudao.module.system.enums.robot.RobotTaskDetailStatusEnum;
import cn.iocoder.yudao.module.system.enums.robot.RobotTaskStatusEnum;
import cn.iocoder.yudao.module.system.enums.robot.RobotTaskTypeEnum;
import cn.iocoder.yudao.module.system.service.robot.RobotTaskService;
import cn.iocoder.yudao.module.system.util.redis.RedisUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static com.baomidou.mybatisplus.core.toolkit.IdWorker.getId;

@Service
@Slf4j
public class CycleServiceImpl implements CycleService {

    @Resource
    private RobotTaskMapper taskMapper;

    @Resource
    private RobotTaskDetailMapper taskDetailMapper;

    @Autowired
    private ZnConfigConstant znConfigConstant;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private WareHouseLocationMapper locationMapper;

    @Resource
    private RobotTaskService robotTaskService;

    @Resource
    private TaskCycleMapper taskCycleMapper;
    /**
     * 创建循环任务
     */
    @Override
    public void cycleTaskJob() {
        TenantContextHolder.setTenantId(1L);

        if (!znConfigConstant.getDoCycle()) {
            log.info("循环任务关闭了--不自动创建循环任务");
        }

        List<RobotTaskDetailDO> detailDOS = taskDetailMapper.selectAutoCreateCycleTask();

        if (ObjectUtil.isEmpty(detailDOS)) {
            log.info("---不存在需要自动创建循环的任务--");
            return;
        }

        Set<Long> taskIds = detailDOS.stream().map(RobotTaskDetailDO::getRobotTaskId).collect(Collectors.toSet());

        List<RobotTaskDO> taskList = taskMapper.selectList(new LambdaQueryWrapper<RobotTaskDO>()
                .in(RobotTaskDO::getId, taskIds)
                .orderByAsc(RobotTaskDO::getCreateTime));

        Map<Long, List<RobotTaskDetailDO>> taskIdMap =
                detailDOS.stream().collect(Collectors.groupingBy(RobotTaskDetailDO::getRobotTaskId));



        List<RobotTaskDO> taskDOList = new ArrayList<>();
        List<RobotTaskDetailDO> taskDetailList = new LinkedList<>();
        for (RobotTaskDO v : taskList) {
            String incrementByKey = redisUtil.getIncrementByKey(RobotCacheLockEnum.TASK_NO.getKey());
            RobotTaskDO taskData = getTaskData(incrementByKey, v);
            List<RobotTaskDetailDO> taskDetailDOS = getTaskDetailData(taskData,taskIdMap,v.getId());
            taskDOList.add(taskData);
            taskDetailList.addAll(taskDetailDOS);
            v.setRemainingCycleNumber(0l);
        }

        taskMapper.insert(taskDOList);
        taskMapper.updateById(taskList);

        List<RobotTaskDetailDO> moves = taskDetailList.stream().filter(v -> RobotTaskTypeEnum.MOVE_TO_POINT.getType().equals(v.getTaskType())).collect(Collectors.toList());
        List<RobotTaskDetailDO> takes = taskDetailList.stream().filter(v -> !RobotTaskTypeEnum.MOVE_TO_POINT.getType().equals(v.getTaskType())).collect(Collectors.toList());
        List<RobotTaskDetailDO> taskDetails= new LinkedList<>();
        if (ObjectUtil.isNotEmpty(moves)) {
            taskDetails.addAll(moves);
        }
        if (ObjectUtil.isNotEmpty(takes)) {
            Collections.reverse(takes);
            taskDetails.addAll(takes);
        }

        taskDetailMapper.insert(taskDetails);

        List<Long> fromLocationIds = taskDetailList.stream().map(RobotTaskDetailDO::getFromLocationId).collect(Collectors.toList());
        List<Long> toLocationIds = taskDetailList.stream().map(RobotTaskDetailDO::getToLocationId).collect(Collectors.toList());
        List<Long> locationIds = new ArrayList<>();
        locationIds.addAll(fromLocationIds);
        locationIds.addAll(toLocationIds);

        List<List<Long>> fromPartition = Lists.partition(locationIds, 100);
        fromPartition.forEach(list -> {
            locationMapper.updateLocationLockList(list, -1l, LocationLockEnum.NO.getType());
        });

        List<RobotTaskDetailAddVO> bean = BeanUtils.toBean(taskDetails, RobotTaskDetailAddVO.class);
        Map<Long, List<RobotTaskDetailAddVO>> taskDetailMap =
                bean.stream().collect(Collectors.groupingBy(RobotTaskDetailAddVO::getRobotTaskId));
        /*taskDetailMap.forEach((k,v) ->{
            robotTaskService.addCycle(k,v);
        });*/
        taskCycleMapper.deletByRobotTaskIds(taskIds);
        setTaskUnDo();
    }

    public void setTaskUnDo() {
        List<RobotTaskDetailDO> detailDOS = taskDetailMapper.selectAutoCreateCycleTaskForever();
        if (ObjectUtil.isEmpty(detailDOS)) {
            return;
        }
        List<Long> detailIds = new ArrayList<>();
        Set<Long> taskIds = new HashSet<>();
        for (RobotTaskDetailDO detail : detailDOS) {
            detailIds.add(detail.getId());
            taskIds.add(detail.getRobotTaskId());
        }
        taskDetailMapper.setTaskUnDo(detailIds);
        taskMapper.setTaskUnDo(taskIds);
    }

    private List<RobotTaskDetailDO> getTaskDetailData(RobotTaskDO taskData, Map<Long,
            List<RobotTaskDetailDO>> taskIdMap, Long id) {

        List<RobotTaskDetailDO> taskDetailDOList = new LinkedList<>();
        List<RobotTaskDetailDO> taskDetailDOS = taskIdMap.get(id);
        for (RobotTaskDetailDO v : taskDetailDOS) {
            RobotTaskDetailDO build = RobotTaskDetailDO.builder()
                    .robotTaskId(taskData.getId())
                    .taskType(v.getTaskType())
                    .releaseType(v.getTakeType())
                    .takeType(v.getReleaseType())
                    .releaseId(v.getTakeId())
                    .takeId(v.getReleaseId())
                    .robotNo(v.getRobotNo())
                    .fromLocationNo(v.getToLocationNo())
                    .fromLocationId(v.getToLocationId())
                    .fromLaneId(v.getToLaneId())
                    .toLaneId(v.getFromLaneId())
                    .toLocationNo(v.getFromLocationNo())
                    .toLocationId(v.getFromLocationId())
                    .fromLocationStorey(v.getToLocationStorey())
                    .toLocationStorey(v.getFromLocationStorey())
                    .priority(v.getPriority())
                    .taskStatus(RobotTaskDetailStatusEnum.NEW.getType())
                    .taskStage(0l)
                    .needLock(v.getNeedLock())
                    .startTime(null)
                    .endTime(null)
                    .fromLocationNumber(v.getToLocationNumber())
                    .toLocationNumber(v.getFromLocationNumber())
                    .fromMapItemId(v.getToMapItemId())
                    .toMapItemId(v.getFromMapItemId())
                    .build();

            if (RobotTaskTypeEnum.MOVE_TO_POINT.getType().equals(build.getTaskType())) {
                build.setToLocationNo(v.getToLocationNo());
                build.setToLocationId(v.getToLocationId());
                build.setReleaseId(v.getReleaseId());
                build.setFromLocationNo(null);
                build.setFromLocationId(null);
                build.setTakeId(null);
            }

            taskDetailDOList.add(build);
        }

        return taskDetailDOList;
    }

    /**
     * 设置任务主表数据
     * @param incrementByKey
     * @param v
     * @return
     */
    public RobotTaskDO getTaskData(String incrementByKey, RobotTaskDO v ) {
        String taskNoStr = znConfigConstant.getTaskNo() + DateUtils.getYearMonthDay() + incrementByKey;
        RobotTaskDO task = new RobotTaskDO();
        BeanUtils.copyProperties(v, task);
        task.setRemainingCycleNumber(v.getRemainingCycleNumber() - 1);
        task.setTaskNo(taskNoStr);
        task.setTaskStatus(RobotTaskStatusEnum.NEW.getType());
        task.setTaskStage(0l);
        task.setStartTime(null);
        task.setEndTime(null);
        task.setCreateTime(LocalDateTime.now());
        task.setUpdateTime(LocalDateTime.now());
        task.setId(getId());
        return task;
    }





































}
