package com.prolog.eis.service.carry.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.prolog.eis.constants.base.BaseBillTypeConstants;
import com.prolog.eis.constants.base.OrderStatusConstants;
import com.prolog.eis.constants.sys.SysParamConstants;
import com.prolog.eis.constants.wms.WmsConstants;
import com.prolog.eis.dao.outbound.BizOutboundTaskDetailMapper;
import com.prolog.eis.dao.outbound.BizOutboundTaskMapper;
import com.prolog.eis.dto.item.ItemSyncVO;
import com.prolog.eis.enums.base.BaseStatusEnum;
import com.prolog.eis.enums.wms.WmsCarryTaskInCode;
import com.prolog.eis.model.container.ContainerInfo;
import com.prolog.eis.model.container.ContainerTask;
import com.prolog.eis.model.outbound.BizOutboundTask;
import com.prolog.eis.model.outbound.BizOutboundTaskDetail;
import com.prolog.eis.service.carry.TimeTaskService;
import com.prolog.eis.service.container.ContainerInfoService;
import com.prolog.eis.service.container.ContainerTaskService;
import com.prolog.eis.service.core.OutboundService;
import com.prolog.eis.service.feign.FeignGoodsService;
import com.prolog.framework.core.restriction.Criteria;
import com.prolog.framework.core.restriction.Restrictions;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zmr
 * @description: 出库任务表-服务实现类
 * @date 2023-07-06 11:36
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class TimeTaskServiceImpl implements TimeTaskService {

    private final OutboundService outboundService;
    private final BizOutboundTaskMapper bizOutboundTaskMapper;
    private final BizOutboundTaskDetailMapper bizOutboundTaskDetailMapper;
    private final ContainerTaskService containerTaskService;
    private final ContainerInfoService containerInfoService;
    private final FeignGoodsService feignGoodsService;
    private final RedisTemplate redisTemplate;



    @Override
    public void sendOutCarry() throws Exception {
        //查询待出库订单
        Criteria criteria = new Criteria(BizOutboundTask.class);
        criteria.setRestriction(Restrictions.ne("wmsLocationCode", WmsConstants.AGVL).and(Restrictions.ne("billType", BaseBillTypeConstants.REPLENISH_TYPE)).and(Restrictions.eq("status",OrderStatusConstants.START_STATUS)));
        List<BizOutboundTask> outTaskList = bizOutboundTaskMapper.findByCriteria(criteria);
        //无出库任务直接返回
        if(outTaskList.isEmpty()) {
            log.debug("暂无可执行出库任务");
            return;
        }
        //优先级排序
        outTaskList = outTaskList.stream().sorted(Comparator.comparing(BizOutboundTask::getPriority)
                .thenComparing(BizOutboundTask::getCreateTime)).collect(Collectors.toList());

        for (BizOutboundTask task : outTaskList) {
            try {
                doWmsOutTask(task);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
    }



    private void doWmsOutTask(BizOutboundTask outTask) throws Exception {
        Criteria criteria = Criteria.forClass(ContainerTask.class);
        criteria.restrictionBuilder().eq(ContainerTask::getStatus, BaseStatusEnum.STATUS_INIT.getCode())
                .eq(ContainerTask::getOutboundId, outTask.getId())
                /*.eq(ContainerTask::getWarehouseArea, WmsLocationCodeConstants.SX01)*/.build();
        List<ContainerTask> containerTaskList = containerTaskService.findByCriteria(criteria);
        if (CollectionUtil.isEmpty(containerTaskList)) {
            throw new Exception("没有等待发送的四向库出库任务");
        }
        Set<String> containerSet = containerTaskList.stream().map(ContainerTask::getContainerSubNo).collect(Collectors.toSet());

        for (String containerNo : containerSet) {
           outboundService.doWmsOutTask(outTask,containerNo,containerTaskList);
        }

        //查询当前订单详情是否都完成
        //更新任务状态
        Criteria criteria1 = new Criteria(BizOutboundTaskDetail.class);
        criteria1.setRestriction(Restrictions.in("status",new Integer[]{BaseStatusEnum.STATUS_INIT.getCode(),BaseStatusEnum.STATUS_STARTED.getCode()})
                .and(Restrictions.eq("outboundId",outTask.getId())));
        long count = bizOutboundTaskDetailMapper.findByCriteria(criteria1).stream().collect(Collectors.counting());
        if(count == 0){
            outTask.setStatus(BaseStatusEnum.STATUS_CARRY.getCode());
            outTask.setUpdateTime(LocalDateTime.now());
            bizOutboundTaskMapper.update(outTask);
        }
    }

    @Override
    public void supplyGen() throws Exception {
        //查询待补货出库订单
        Criteria criteria = new Criteria(BizOutboundTask.class);
        criteria.setRestriction(Restrictions.ne("wmsLocationCode", WmsConstants.AGVL).and(Restrictions.eq("billType", BaseBillTypeConstants.REPLENISH_TYPE)).and(Restrictions.eq("status",OrderStatusConstants.START_STATUS)));
        List<BizOutboundTask> outTaskList = bizOutboundTaskMapper.findByCriteria(criteria);
         if (CollectionUtil.isEmpty(outTaskList)) {
            return;
        }
        //查询补货订单容器任务
        List<Integer> outboundIds = outTaskList.stream().map(BizOutboundTask::getId).collect(Collectors.toList());
        criteria = Criteria.forClass(ContainerTask.class);
        criteria.restrictionBuilder().eq(ContainerTask::getStatus, BaseStatusEnum.STATUS_INIT.getCode()).in(ContainerTask::getOutboundId, outboundIds).build();
        List<ContainerTask> containerTaskList = containerTaskService.findByCriteria(criteria);
        if (CollectionUtil.isEmpty(containerTaskList)) {
            return;
        }
        //组装排序条件
        genTaskSort(outTaskList, containerTaskList);
        //排序 按照补货任务创建超过时间的订单优先(超时时间可配置) > 优先做满足订单较多的任务 > 补对应订单明细少的任务 > 按照补货任务ABC属性。
//        containerTaskList = containerTaskList.stream().sorted(Comparator.comparing(ContainerTask::getIsTimeOut).reversed()
//                .thenComparing(ContainerTask::getOrderNum, Comparator.reverseOrder())
//                .thenComparing(ContainerTask::getOrderDetailNum)
//                .thenComparing(ContainerTask::getAbcType)
//        ).collect(Collectors.toList());
        containerTaskList = containerTaskList.stream()
                .sorted(Comparator.comparing(ContainerTask :: getPriorty,Comparator.nullsLast(Integer :: compareTo)).reversed()
                .thenComparing(ContainerTask :: getOrderNum, Comparator.reverseOrder())
                .thenComparing(ContainerTask :: getIsTimeOut, Comparator.reverseOrder())
                .thenComparing(ContainerTask :: getOrderDetailNum)
                .thenComparing(ContainerTask :: getAbcType)
        ).collect(Collectors.toList());
        List<String> sendTask = new ArrayList<>();
        for (ContainerTask containerTask : containerTaskList) {
            if (sendTask.contains(containerTask.getContainerNo())) {
                continue;
            }
            List<ContainerTask> containerTasks = containerTaskList.stream().filter(item -> StrUtil.equals(item.getContainerNo(), containerTask.getContainerNo())).collect(Collectors.toList());
            Long count = additionalTaskLogic(containerTask.getContainerNo());
            ContainerInfo containerInfo = containerInfoService.findOneByContainerNo(containerTask.getContainerNo());
            if (count > 0 || containerInfo.getTaskType() != 0) {
                log.info(String.format("发送出库搬运任务：托盘：[%s]正在搬运，等待中", containerTask.getContainerNo()));
                continue;
            }
            try {
                outboundService.doGenTask(containerTask, outTaskList, containerTasks, sendTask);
            } catch (Exception e) {
                log.error("补货任务生成失败：{}", e.getMessage(), e);
            }
        }
    }


    private Long additionalTaskLogic(String containerNo) {
        Criteria criteria = Criteria.forClass(ContainerTask.class);
        criteria.restrictionBuilder().gt(ContainerTask::getStatus, BaseStatusEnum.STATUS_INIT.getCode())
                .eq(ContainerTask::getContainerNo, containerNo).build();
        Long count = containerTaskService.findCountByCriteria(criteria);
        return count;
    }
    private void genTaskSort(List<BizOutboundTask> outTaskList, List<ContainerTask> containerTaskList) throws Exception {
        //组装超时补货订单
        int timeOut = Integer.parseInt(String.valueOf(redisTemplate.opsForValue().get(SysParamConstants.SYSPRE_FIX + SysParamConstants.SUPPLY_TIMEOUT_PRIORITY)));
        List<Integer> outboundIds = outTaskList.stream().filter(item -> item.getCreateTime().isBefore(LocalDateTime.now().minusMinutes(timeOut))).map(BizOutboundTask::getId).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(outboundIds)) {
            List<ContainerTask> containerTasks = containerTaskList.stream().filter(item -> outboundIds.contains(item.getOutboundId())).collect(Collectors.toList());
            containerTasks.forEach(item->item.setIsTimeOut(1));
        }
        //组装满足订单数和 满足的订单明细数量最少的明细数量
        Criteria criteria = new Criteria(BizOutboundTask.class);
        criteria.restrictionBuilder().eq(BizOutboundTask::getStatus, OrderStatusConstants.INIT_STATUS)
                .eq(BizOutboundTask::getIsLock, 0)
                .eq(BizOutboundTask::getWmsLocationCode, WmsCarryTaskInCode.AGVL.getCode()).build();
        List<BizOutboundTask> outboundTaskList = bizOutboundTaskMapper.findByCriteria(criteria);

        if (CollectionUtil.isNotEmpty(outboundTaskList)) {

            List<Integer> outIds = outboundTaskList.stream().map(BizOutboundTask::getId).collect(Collectors.toList());
            criteria = new Criteria(BizOutboundTaskDetail.class);
            criteria.restrictionBuilder().eq(BizOutboundTaskDetail::getStatus, OrderStatusConstants.INIT_STATUS)
                    .in(BizOutboundTaskDetail::getOutboundId, outIds).build();
            List<BizOutboundTaskDetail> outboundTaskDetails = bizOutboundTaskDetailMapper.findByCriteria(criteria);

            if (CollectionUtil.isNotEmpty(outboundTaskDetails)) {
                Map<String, List<BizOutboundTaskDetail>> collect = outboundTaskDetails.stream().collect(Collectors.groupingBy(o -> o.getBusinessProperty2()));
                Map<Integer, List<BizOutboundTaskDetail>> collect1 = outboundTaskDetails.stream().collect(Collectors.groupingBy(BizOutboundTaskDetail::getOutboundId));
                for (ContainerTask containerTask : containerTaskList) {
                    List<BizOutboundTaskDetail> outboundTaskDetails1 = collect.get(containerTask.getBusinessProperty());
                    if (CollectionUtil.isNotEmpty(outboundTaskDetails1)) {
                        List<Integer> detailCount = new ArrayList<>();
                        containerTask.setOrderNum(outboundTaskDetails1.size());
                        for (BizOutboundTaskDetail bizOutboundTaskDetail : outboundTaskDetails1) {
                            List<BizOutboundTaskDetail> outboundTaskDetails2 = collect1.get(bizOutboundTaskDetail.getOutboundId());
                            if (CollectionUtil.isNotEmpty(outboundTaskDetails2)) {
                                detailCount.add(outboundTaskDetails2.size());
                            }
                        }
                        Collections.sort(detailCount);
                        containerTask.setOrderDetailNum(detailCount.get(0));
                    }
                }
            }
        }
        //组装ABC属性
        List<String> itemIds = containerTaskList.stream().map(ContainerTask::getItemId).distinct().collect(Collectors.toList());
        Map<String,ItemSyncVO> itemMap = feignGoodsService.queryItemMst(itemIds).stream().collect(Collectors.toMap(ItemSyncVO::getItemId, o -> o));
        for (ContainerTask containerTask : containerTaskList) {
            ItemSyncVO itemSyncVO = itemMap.get(containerTask.getItemId());
            containerTask.setAbcType(itemSyncVO.getAbcType());
        }
    }

}
