package com.prolog.upcloud.base.wh.operate.service.impl.eis;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
import com.prolog.common.RestMsgHelper;
import com.prolog.cs.basic.item.model.vo.WaveItemInfoVO;
import com.prolog.cs.biz.outbound.model.dto.InfTaskOutBackDTO;
import com.prolog.cs.biz.outbound.model.vo.EisCheckBackDetailVo;
import com.prolog.cs.platform.power.model.Employee;
import com.prolog.entity.vo.*;
import com.prolog.enums.OperationCompleteEnum;
import com.prolog.enums.OutboundTaskCallbackEnum;
import com.prolog.framework.authority.core.dto.UserDTO;
import com.prolog.framework.authority.user.UserTemplate;
import com.prolog.framework.authority.util.HystrixVarUtil;
import com.prolog.framework.common.message.RestMessage;
import com.prolog.framework.core.exception.BizException;
import com.prolog.framework.core.exception.ParameterException;
import com.prolog.inte.WmsHandler;
import com.prolog.upcloud.base.wh.operate.resource.*;
import com.prolog.upcloud.base.wh.operate.service.InvCheckService;
import com.prolog.upcloud.base.wh.operate.service.MqOperateProducer;
import com.prolog.upcloud.base.wh.operate.service.WmsReplenishService;
import com.prolog.upcloud.base.wh.operate.vo.MoveConfirmParamsVO;
import com.prolog.upcloud.base.wh.operate.vo.ReplenishPreVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.prolog.constant.WmsBusinessConstant.*;


@Slf4j
@Component
public class WmsOperateHandler implements WmsHandler {

    @Resource
    private InvCheckService checkService;

    @Resource
    private MqOperateProducer producer;

    @Resource
    private OutBoundClient outBoundClient;
    @Resource
    private StockResource stockResource;
    @Autowired
    WmsReplenishService wmsReplenishService;
    @Autowired
    GspClient gspClient;
    @Autowired
    private PlatformPowerClient platformPowerClient;
    @Autowired
    private UserTemplate userTemplate;
    @Autowired
    private ItemResource itemResource;

    /**
     * 作业到位回告
     */
    public void outboundTaskCallback(List<OutboundTaskCallbackVO> list) {
        log.info("start dispatch outboundTaskCallback.params:{}", JSONObject.toJSONString(list));

        for (OutboundTaskCallbackVO vo : list) {
            Map<String, List<OutboundTaskCallbackItemVO>> taskList = vo.getSubList().stream().collect(Collectors.groupingBy(OutboundTaskCallbackItemVO::getBusinessType));

            List<OutboundTaskCallbackItemVO> checkTasks = taskList.get(OutboundTaskCallbackEnum.INV_PLANCHECK.getBusinessType());
            //盘点回告
            if (CollUtil.isNotEmpty(checkTasks)) {
                taskList.remove(OutboundTaskCallbackEnum.INV_PLANCHECK.getBusinessType());
                vo.setSubList(checkTasks);
                log.info("outboundTaskCallback.checkTasks:{}", JSONObject.toJSONString(vo));
                checkService.updateStatus4CheckByEis(vo);
            }

            List<OutboundTaskCallbackItemVO> conserves = taskList.get(OutboundTaskCallbackEnum.INV_CONSERVE.getBusinessType());
            //养护回告
            if (CollUtil.isNotEmpty(conserves)) {
                taskList.remove(OutboundTaskCallbackEnum.INV_CONSERVE.getBusinessType());
                vo.setSubList(conserves);
                log.info("outboundTaskCallback.conserves:{}", JSONObject.toJSONString(vo));
                producer.gspTaskCallback(vo);
            }

            //剩下的是出库任务
            Collection<List<OutboundTaskCallbackItemVO>> values = taskList.values();
            //出库回告
            if (CollUtil.isNotEmpty(values)) {
                List<OutboundTaskCallbackItemVO> pickTasks = values.stream().map(ArrayList::new).flatMap(List::stream).collect(Collectors.toList());
                vo.setSubList(pickTasks);
                log.info("outboundTaskCallback.pickTasks:{}", JSONObject.toJSONString(vo));
                producer.outboundTaskCallback(vo);
            }
        }
        log.info("end dispatch outboundTaskCallback");
    }

    /**
     * 作业完成回告
     * 采购入库/销售退货（）：
     * （1）二楼阴凉AGV拆零区：WMS指定品批出库，EIS计算命中AGV拆零托盘还是AGV货架进行总拣下架。
     * EIS内部做拣选作业，WMS不需要回告EIS作业完成确认，EIS拣选完成后通过作业完成通知接口回告
     * 拆零拣选环节总拣、零发整出库拣选环节总拣时按照容器维度回告WMS；
     */

    public Map<String, Object> completeTask(List<CompleteTaskVO> list) {
        log.info("completeTask.params:{}", JSONObject.toJSONString(list));
        Assert.notEmpty(list, "参数不能为空");

        CompleteTaskVO vo = list.get(0);

        Employee employee = RestMsgHelper.getData(platformPowerClient.getByNum(vo.getEmployeeId(), vo.getWarehouseId(), "900356013474058240"));
        cn.hutool.core.lang.Assert.notNull(employee, "根据工号【{}】获取员工信息失败", vo.getEmployeeId());

        getUserDtoKeyAndSetCache(employee.getUsername());
        String separator = "###";

        Map<String, List<CompleteTaskVO>> map = list.stream().collect(Collectors.groupingBy(t -> t.getBusinessType() + separator + t.getWorkType()));
        for (String s : map.keySet()) {

            String[] split = s.split(separator);
            OperationCompleteEnum completeEnum = OperationCompleteEnum.get(split[1], split[0]);
            cn.hutool.core.lang.Assert.notNull(completeEnum, "获取出库完成枚举失败");

            if (DO_SO.equals(completeEnum.name()) || DO_RCVRETURN.equals(completeEnum.name())) {
                return RestMsgHelper.getData(outBoundClient.completeTask(list));
            }
            //补货
            if (INV_RTM.equals(completeEnum.name())) {
                MoveConfirmParamsVO confirmParamsVO = new MoveConfirmParamsVO();
                List<CompleteTaskVO> completeTaskVOS = map.get(s);
                CompleteTaskVO completeTaskVO = completeTaskVOS.get(0);
                confirmParamsVO.setLineId(completeTaskVO.getTaskLineId());
                confirmParamsVO.setTaskId(completeTaskVO.getTaskId());
                confirmParamsVO.setContainerNo(completeTaskVO.getContainerNo());
                confirmParamsVO.setInventoryQty(completeTaskVO.getInventoryQty());
                wmsReplenishService.autoConfirmReplenish(confirmParamsVO);
                return null;
            }
            //盘点
            if (INV_PLANCHECK.equals(completeEnum.name())) {
                checkService.eisBackUpdateCheckD(map.get(s));
                return null;
            }
            //养护
            if (INV_CONSERVE.equals(completeEnum.name())) {
                gspUpKeepOutBack(map.get(s));
                return null;
            }
        }

        return null;
    }

    public UserDTO getUserDtoKeyAndSetCache(String printName) {

        UserDTO userDTO = userTemplate.getUserDTO();
        if (userDTO != null) {
            return userDTO;
        }

        HystrixRequestContext.initializeContext();
        HystrixVarUtil.setUserKey(printName);
        userDTO = userTemplate.getUserDTO();
        log.info("getUserDtoKey:{}", JSONObject.toJSONString(userDTO));
        if (userDTO != null) {
            return userDTO;
        }
        return null;
    }

    private void gspUpKeepOutBack(List<CompleteTaskVO> completeTaskVOS) {
        if(CollectionUtil.isEmpty(completeTaskVOS)){
            return;
        }
        List<InfTaskOutBackDTO> upkeepList = completeTaskVOS.stream().map(t ->{
            InfTaskOutBackDTO infTaskOutBackDTO = new InfTaskOutBackDTO();
            infTaskOutBackDTO.setSeqNo(t.getTaskLineId());
            List<EisCheckBackDetailVo> itemList = t.getItemList().stream().map(i -> {
                EisCheckBackDetailVo eisCheckBackDetailVo = new EisCheckBackDetailVo();
                BeanUtils.copyProperties(i,eisCheckBackDetailVo);
                eisCheckBackDetailVo.setInventoryQty(BigDecimal.valueOf(i.getInventoryQty()));
                return eisCheckBackDetailVo;
            }).collect(Collectors.toList());
            infTaskOutBackDTO.setItemList(itemList);
            return infTaskOutBackDTO;
        }).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(upkeepList)) {
            log.info("作业完成回告（养护回告）入参：{}",JSONObject.toJSONString(upkeepList));
            RestMessage restMessage = gspClient.gspUpKeepOutBack(upkeepList);
            if (!restMessage.isSuccess()) {
                throw new BizException("养护回告失败！" + restMessage.getMessage());
            }
        }
    }

    /**
     * EIS开始完成容器借道任务后，反馈WMS借道任务完成
     * WMS进行上架确认、拣货确认、集货等业务逻辑处理
     */
    @Override
    public void containerTailgatingFeedback(ContainerTailgatingFeedbackVO vo) {
        log.info("containerTailgatingFeedback.params:{}", JSONObject.toJSONString(vo));
        producer.containerTailgatingFeedback(vo);
    }

    /**
     * 正常出库(销售出库、购进退货出库)：
     * 拆零库区订单绑定分拣机格口成功后，EIS反馈订单与格口绑定关系至青牛系统；
     */
    @Override
    public void orderBindingGridFeedback(OrderBindingGridFeedbackVO vo) {
        log.info("orderBindingGridFeedback.params:{}", JSONObject.toJSONString(vo));
        producer.orderBindingGridFeedback(vo);
    }

    /**
     * 出库复核结果回传
     * 正常出库(销售出库、购进退货出库)：
     * 拆零库区订单所属商品全部供包上线后，EIS回传拆零订单所属商品出库复核结果（订单信息及药监码集合）
     * 是否可以通过此接口申请打印出库清单、发票
     */
    @Override
    public void outboundCheckResultCallback(OutboundCheckResultCallbackVO vo) {
        log.info("outboundCheckResultCallback.params:{}", JSONObject.toJSONString(vo));
        if (vo != null) {
            producer.outboundCheckResultCallback(vo);
        }
    }

    /**
     * 申请面单打印
     * 正常出库(销售出库、购进退货出库)：
     * 拆零库区订单所属商品全部供包上线后，EIS申请WMS订单面单信息打印，申请信息包含订单及格口号，WMS负责推送相应格口区域打印机打印面单信息；
     */
    @Override
    public void applyForDocumentPrinting(ApplyForDocumentPrintingVO vo) {
        log.info("applyForDocumentPrinting.params:{}", JSONObject.toJSONString(vo));
//        /print/print-expressData
        producer.applyForDocumentPrinting(vo);
    }

    /**
     * 托盘回库变更申请
     * 补货：
     * 由四向库补货上架托盘在拆零库区补货完成后，回库前，优先申请回库变更为阴凉托盘区（储位空闲率较高-系统参数）不在回四向库区
     * WMS反馈可用库存与EIS剩余容器库存做比较
     * WMS反馈库存大于等于EIS剩余容器库存，可以更换存储区
     * WMS反馈库存小于EIS剩余容器库存，必须回四向库存储
     */
    @Override
    public void applyForContainerReturnChange(ApplyForContainerReturnChangeVO vo) {
        log.info("applyForContainerReturnChange.params:{}", JSONObject.toJSONString(vo));
//        /external/applyForContainerReturnChange
        RestMsgHelper.runAndGet(() -> stockResource.applyForContainerReturnChange(vo));
    }

    /**
     * 分拣滑道请求分配
     * 正常出库(销售出库、购进退货出库)：
     * 拆零区订单出库需在1F扫描包裹号分配请求WMS滑道；WMS同步反馈滑道；
     */
    @Override
    public void applyForPickSlide(ApplyForPickSlideVO vo) {
        log.info("applyForPickSlide.params:{}", JSONObject.toJSONString(vo));
//        /inner/check/v2/getSlideNoByMailNo;
        throw new UnsupportedOperationException();
    }

    @Override
    public Map<String, Object> applyForPackageWeigh(ApplyForPackageWeighVO vo) {
        return RestMsgHelper.getData(outBoundClient.applyForPackageWeigh(vo));
    }

    @Override
    public MarkTaskVO markTask(MarkTaskVO vo) {
        checkMarkTaskVo(vo);
        List<MarkTaskItemVO> subList = vo.getSubList();
        //超补列表
        List<MarkTaskItemVO> exceeds = subList.stream().filter(item -> item.getExceedQyt().compareTo(BigDecimal.ZERO) > 0).collect(Collectors.toList());
        //缺货列表
        List<MarkTaskItemVO> lacks = subList.stream().filter(item -> item.getLackQty().compareTo(BigDecimal.ZERO) > 0).collect(Collectors.toList());

        List<MarkTaskItemVO> exceedList = new ArrayList<>();
        if(exceeds != null && exceeds.size() > 0){
            Map<String, List<MarkTaskItemVO>> map = exceeds.stream().collect(Collectors.groupingBy(MarkTaskItemVO::getTaskLineId));
            for (Map.Entry<String, List<MarkTaskItemVO>> entry : map.entrySet()) {
                List<MarkTaskItemVO> value = entry.getValue();
                MarkTaskItemVO itemVO = value.get(0);
                itemVO.setExceedQyt(value.stream().map(MarkTaskItemVO::getExceedQyt).reduce(BigDecimal.ZERO, BigDecimal::add));
                List<String> containerNos = value.stream().map(MarkTaskItemVO::getContainerNo).collect(Collectors.toList());
                if(containerNos.size() > 0){
                    itemVO.setContainerNo(String.join(",",containerNos));
                }

                exceedList.add(itemVO);
            }
//            //查询商品信息
//            List<String> itemIds = exceedList.stream().map(MarkTaskItemVO::getItemId).distinct().collect(Collectors.toList());
//            RestMessage<List<WaveItemInfoVO>> itemInfoMsg = itemResource.getWaveItemInfo(itemIds);
//            if(itemInfoMsg == null || !itemInfoMsg.isSuccess()){
//                throw new BizException("调用item服务查询商品信息失败!");
//            }
//            List<WaveItemInfoVO> waveItemInfoVOS = itemInfoMsg.getData();
//            if(waveItemInfoVOS == null || waveItemInfoVOS.size() <= 0){
//                throw new BizException("商品id:"+JSONObject.toJSONString(itemIds)+"不存在!");
//            }
//            log.info("超补，查询商品列表：{}", JSON.toJSONString(waveItemInfoVOS));
//            //A品
//            List<String> aTypeItems = waveItemInfoVOS.stream().filter(item -> "A".equals(item.getAbcType())).map(WaveItemInfoVO :: getItemId).collect(Collectors.toList());
//            if(aTypeItems == null || aTypeItems.size() <= 0){
//                throw new BizException("BC品不允许超补!");
//            }
//            boolean anyMatch = exceedList.stream().anyMatch(item -> !aTypeItems.contains(item.getItemId()));
//            if(anyMatch){
//                throw new BizException("BC品不允许超补!");
//            }
            List<MarkTaskItemVO> exceedSubList = wmsReplenishService.exceedTask(exceedList);
            vo.setExceedSubList(exceedSubList);
        }
        if(lacks != null && lacks.size() > 0){

        }
        return vo;
    }

    private void checkMarkTaskVo(MarkTaskVO vo) {
        if(StringUtils.isEmpty(vo.getMsgId())){
            throw new ParameterException("msgId不能为空!");
        }
        List<MarkTaskItemVO> subList = vo.getSubList();
        if(subList == null || subList.size() <= 0){
            throw new BizException("subList不能为空!");
        }
        List<MarkTaskItemVO> subList2 = new ArrayList<>();
        for (MarkTaskItemVO itemVO : subList) {
            if(StringUtils.isEmpty(itemVO.getTaskLineId())){
                log.info("taskLineId不能为空！");
                continue;
            }

            if(itemVO.getQty() == null){
                log.info("qty不能为空！");
                continue;
            }

            if(itemVO.getExceedQyt() == null){
                itemVO.setExceedQyt(BigDecimal.ZERO);
            }
            if(itemVO.getLackQty() == null){
                itemVO.setLackQty(BigDecimal.ZERO);
            }
            subList2.add(itemVO);
        }
        vo.setSubList(subList2);
    }
}
