package com.prolog.cs.biz.outbound.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.prolog.cs.biz.outbound.dao.*;
import com.prolog.cs.biz.outbound.model.OmsDoBillHDO;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.prolog.cs.biz.outbound.dao.OmsPackingDataMapper;
import com.prolog.cs.biz.outbound.dao.OutcomingRecordDMapper;
import com.prolog.cs.biz.outbound.dao.OutcomingRecordHMapper;
import com.prolog.cs.biz.outbound.dao.WaveBillMapper;
import com.prolog.cs.biz.outbound.model.OmsPackingData;
import com.prolog.cs.biz.outbound.model.OutcomingRecordD;
import com.prolog.cs.biz.outbound.model.OutcomingRecordH;
import com.prolog.cs.biz.outbound.model.dto.OutcomingRecordHDto;
import com.prolog.cs.biz.outbound.model.entity.BarcodeHDO;
import com.prolog.cs.biz.outbound.model.entity.OmsDoBillDDO;
import com.prolog.cs.biz.outbound.model.entity.WorkStageRuntimeDO;
import com.prolog.cs.biz.outbound.model.vo.InfTaskOutBackVO;
import com.prolog.cs.biz.outbound.model.vo.check.PackgeBackDVO;
import com.prolog.cs.biz.outbound.model.vo.check.PackgeBackHVO;
import com.prolog.cs.biz.outbound.resource.InventoryResource;
import com.prolog.cs.biz.outbound.resource.StrategyResource;
import com.prolog.cs.biz.outbound.service.PostBackErpService;
import com.prolog.cs.data.exchange.client.ExchangeSender;
import com.prolog.cs.data.exchange.client.core.EtlMessage;
import com.prolog.cs.data.exchange.client.core.EtlTypeConstants;
import com.prolog.framework.authority.user.UserTemplate;
import com.prolog.framework.bz.core.v1.user.UserUtils;
import com.prolog.framework.common.message.RestMessage;
import com.prolog.framework.core.annotation.AutoKey;
import com.prolog.framework.core.exception.BizException;
import com.prolog.framework.core.restriction.Criteria;
import com.prolog.framework.core.restriction.Restriction;
import com.prolog.framework.core.restriction.Restrictions;
import com.prolog.framework.utils.DateUtils;
import com.prolog.framework.utils.MapUtils;
import com.prolog.framework.utils.StringUtils;
import com.prolog.upcloud.base.inventory.vo.AskIntegrationVo;
import com.prolog.upcloud.base.inventory.vo.InvStockCheckOut;
import com.prolog.upcloud.base.strategy.model.BusinessControl;
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 org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @program: upcloud-base-wh-outbound
 * @description: 回传ERP服务impl
 * @author: Huanglh
 * @create: 2022-01-14 14:13
 **/
@Service
@Slf4j
public class PostBackErpServiceImpl implements PostBackErpService {
    @Autowired
    private ExchangeSender exchangeSender;

    @Autowired
    private OutcomingRecordHMapper outcomingRecordHMapper;

    @Autowired
    private OutcomingRecordDMapper outcomingRecordDMapper;

    @Autowired
    private WaveBillMapper billMapper;

    @Autowired
    private InventoryResource invClient;

    @Autowired
    private OmsPackingDataMapper omsPackingDataMapper;

    @Autowired
    private StrategyResource strategyResource;

    @Autowired
    private OmsDoBillHMapper omsDoBillHMapper;

    @Autowired
    private OmsDoBillDMapper omsDoBillDMapper;

    @Autowired
    private BarcodeHMapper barcodeHMapper;

    @Autowired
    private UserTemplate userTemplate;

    @Autowired
    private WorkStageRuntimeMapper workStageRuntimeMapper;


    @Value("${prolog.dao.keyGenerator.snowFlake.dataCenterId:15}")
    private long dataCenterId;

    @Value("${prolog.dao.keyGenerator.snowFlake.machineId:2}")
    private long machineId;

    @Value("${oms.outComingRecordBack}")
    private String outComingRecordBack;

    @Autowired
    private PickTaskServiceImpl pickTaskServiceImpl;

//    @Value("${oms.omsPackingBack}")
//    private String omsPackingBack;

    /**
     * 使用消息队列方式回传ERP
     *
     * @param omsBillIds
     * @param errorMsg
     */
    @Override
    public void postBackErpByMq(List<String> omsBillIds, String errorMsg) {
        log.info("回传ERP消息开始发送");
        for (String omsBillId : omsBillIds) {
            this.postBackErpByMq(omsBillId, errorMsg);
        }
    }

    /**
     * 使用消息队列方式回传ERP
     *
     * @param omsBillId
     * @param errorMsg
     */
    @Override
    public void postBackErpByMq(String omsBillId, String errorMsg) {
        EtlMessage etlMessage = new EtlMessage();
        etlMessage.setId(omsBillId);
        etlMessage.setEtlType(EtlTypeConstants.out_do_w2o);
        try {
            exchangeSender.send(etlMessage);
        } catch (Exception e) {
            if (StringUtils.isBlank(errorMsg)) {
                errorMsg = "回传ERP，rabbitmq发送消息失败！";
            }
            throw new BizException(errorMsg);
        }
    }

    /**
     * 使用中间表方式回传ERP
     *
     * @param omsBillIds
     */
    @Override
    @Transactional
    public void postBackErpByTable(List<String> omsBillIds) {
        String[] ids = omsBillIds.toArray(new String[omsBillIds.size()]);
        Criteria crtH = Criteria.forClass(OutcomingRecordH.class);
        Criteria crtD = Criteria.forClass(OutcomingRecordD.class);
        crtH.setRestriction(Restrictions.in("billid", ids));
        crtD.setRestriction(Restrictions.in("billid", ids));
        outcomingRecordHMapper.deleteByCriteria(crtH);
        outcomingRecordDMapper.deleteByCriteria(crtD);
        for (String omsBillId : omsBillIds) {
            List<OutcomingRecordH> listH = outcomingRecordHMapper.getH(omsBillId);
            if (listH.size() > 0) {
                outcomingRecordHMapper.saveBatch(listH);
            }
            List<OutcomingRecordD> listD = outcomingRecordHMapper.getD(omsBillId);
            if (CollUtil.isNotEmpty(listD)) {
                List<String> lineIds = listD.stream().map(OutcomingRecordD::getLineId).distinct().collect(Collectors.toList());
                List<OutcomingRecordD> saveRecordDList = new ArrayList<>();
                if (lineIds.size() > 0) {
                    for (String lineId:lineIds) {
                        // 先找批号不为空的
                        OutcomingRecordD outcomingRecordD = listD.stream().filter(d -> d.getLineId().equals(lineId) && !StringUtils.isBlank(d.getLotNo())).findFirst().orElse(null);
                        if (null == outcomingRecordD) {
                            OutcomingRecordD recordD = listD.stream().filter(d -> d.getLineId().equals(lineId)).findFirst().orElse(null);
                            saveRecordDList.add(recordD);
                        } else {
                            saveRecordDList.add(outcomingRecordD);
                        }
                    }
                }
                if (CollUtil.isNotEmpty(saveRecordDList)) {
                    outcomingRecordDMapper.saveBatch(saveRecordDList);
                }
            }
        }
        // 调用接口平台回传OMS
        try {
            if (StringUtils.isEmpty(outComingRecordBack)) {
                throw new BizException("请求路径配置为空");
            }
            String url = outComingRecordBack;
            log.info("调用OMS接口URL:{}", JSONUtil.toJsonStr(url));
            List<OutcomingRecordHDto> backList = pickTaskServiceImpl.queryOutboundDataToOms(omsBillIds);
            log.info("调用OMS接口入参:{}", JSONUtil.toJsonStr(backList));
            String result = HttpUtil.post(url, JSONObject.toJSONString(backList));
            JSONObject parse = JSONObject.parseObject(result);
            log.info("调用OMS接口返回参数:{}",parse);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 出库拼箱数据保存到中间表
     *
     * @param billGroupIds
     */
    @Override
    @Transactional
    public void postBackOmsPackingData(List<String> billGroupIds) {
        for (String omsBillId : billGroupIds) {
            List<OmsPackingData> listH = outcomingRecordHMapper.getOmsPackingData(omsBillId);
            if (listH.size() > 0) {
                omsPackingDataMapper.saveBatch(listH);
            }
        }
    }

    /**
     * 定时任务回传装箱信息给OMS
     *
     * @param
     */
    @Override
    @Transactional
    public void autoPostBackOmsPackingData() {
        //查询所有未回传的未取消订单
        List<String> noBackOmsBillIds = outcomingRecordHMapper.findNoBackOmsBill();
        String warehouseId = "";
        if(noBackOmsBillIds.size()>0){
            OmsDoBillHDO hdo = omsDoBillHMapper.findById(noBackOmsBillIds.get(0),OmsDoBillHDO.class);
            warehouseId = hdo.getBranchid();
        }
        String point = "2";
        //业务参数配置/出库回传ERP节点 1:内复核回传  2:外复核回传
        RestMessage<Map<String, BusinessControl>> restMessageCode = strategyResource.getControlByCodes(new String[]{"OUT_BACK_ERP_POINT"}, warehouseId, null, "", null);
        if (restMessageCode.isSuccess() && restMessageCode.getData() != null) {
            Map<String, BusinessControl> result = restMessageCode.getData();
            if (result.containsKey("OUT_BACK_ERP_POINT")) {
                point = String.valueOf(result.get("OUT_BACK_ERP_POINT").getRegValue());
            }else {
                throw new BizException("出库回传ERP节点未配置");
            }
        }
        //查询订单是否拣货任务全部完成
        List<String> billIds = new ArrayList<>();
        for (String srcCode : noBackOmsBillIds) {
            List<String> strings = outcomingRecordHMapper.finishPickTaskAll(srcCode, point);
            if(strings.size()>0){
                billIds.addAll(strings);
            }
        }
        if(billIds.size()>0){
            for (String omsBillId : billIds) {
                List<OmsPackingData> listH = outcomingRecordHMapper.getOmsPackingData(omsBillId);
                if (listH.size() > 0) {
                    omsPackingDataMapper.saveBatch(listH);
                }
            }
        }
        List<PackgeBackHVO> resultList = new ArrayList<>();
        //查询所有未回传任务
        List<OmsPackingData> packingDataList = omsPackingDataMapper.findByMap(MapUtils.put("tmsFlag", "0").getMap(), OmsPackingData.class);
        if(packingDataList.size()>0){
            Map<String, List<OmsPackingData>> collect = packingDataList.stream().collect(Collectors.groupingBy(OmsPackingData::getBillid));
            Set<Map.Entry<String, List<OmsPackingData>>> entries = collect.entrySet();
            for (Map.Entry<String, List<OmsPackingData>> entry : entries) {
                String omsBillId = entry.getKey();
                List<OmsPackingData> value = entry.getValue();
                OmsDoBillHDO billHDO = omsDoBillHMapper.findById(omsBillId,OmsDoBillHDO.class);
                List<WorkStageRuntimeDO> byMap = workStageRuntimeMapper.findByMap(MapUtils.put("billGroupId", omsBillId).getMap(), WorkStageRuntimeDO.class);
                List<String> stagecodes = new ArrayList<>();
                if(byMap.size()>0) {
                    stagecodes = byMap.stream().sorted((a, b) -> a.getStageCode().compareTo(b.getStageCode())).map(x -> x.getStageCode()).collect(Collectors.toList());
                }
                PackgeBackHVO packgeBackHVO = new PackgeBackHVO();
                packgeBackHVO.setBillId(billHDO.getBillid());
                packgeBackHVO.setBillNo(billHDO.getBillno());
                packgeBackHVO.setBranchId(billHDO.getBranchid());
                packgeBackHVO.setBillDate(billHDO.getBillDate()==null?null:DateUtils.format(billHDO.getBillDate(),"yyyy-MM-dd HH:mm:ss"));
                packgeBackHVO.setCustomerCode(StringUtils.isEmpty(value.get(0).getShippercode())?"":value.get(0).getShippercode());
                packgeBackHVO.setSalespersonId(StringUtils.isEmpty(billHDO.getSalespersonId())?"":billHDO.getSalespersonId());
                packgeBackHVO.setPickWay(billHDO.getTakeMode()==null?null:billHDO.getTakeMode());
                packgeBackHVO.setPackType(billHDO.getBilltype().equals("1")?"1":"2");
                packgeBackHVO.setConsignorCode(StringUtils.isEmpty(billHDO.getConsignorcode())?"":billHDO.getConsignorcode());
                packgeBackHVO.setConsignorName(StringUtils.isEmpty(billHDO.getConsignorname())?"":billHDO.getConsignorname());
                packgeBackHVO.setStageAreaStart("");
                packgeBackHVO.setStageAreaEnd("");
                if(stagecodes.size()>0){
                    packgeBackHVO.setStageAreaStart(StringUtils.isEmpty(stagecodes.get(0))?"":stagecodes.get(0));
                    packgeBackHVO.setStageAreaEnd(StringUtils.isEmpty(stagecodes.get(stagecodes.size()-1))?"":stagecodes.get(stagecodes.size()-1));
                }
                packgeBackHVO.setCarrierCode(billHDO.getCarrierId());
                packgeBackHVO.setCarrierName(billHDO.getCarrierName());
                packgeBackHVO.setWayBillNo(billHDO.getShipBillNo());
                packgeBackHVO.setEnterpriseId(billHDO.getEnterpriseId());
                packgeBackHVO.setEnterpriseName(billHDO.getEnterpriseName());

                List<PackgeBackDVO> detailList = new ArrayList<>();
                value.stream().forEach(x->{
                    PackgeBackDVO backDVO = new PackgeBackDVO();
                    backDVO.setWmsNo(x.getBoxcode()!=null?x.getBoxcode():"");
                    backDVO.setPackageType(x.getBoxmode());
                    backDVO.setBillNo(x.getBillno());
                    backDVO.setNetWeight(x.getTotweight()==null?BigDecimal.ZERO:x.getTotweight());
                    backDVO.setAcNetWeight(x.getTotweight()==null?BigDecimal.ZERO:x.getTotweight());
                    backDVO.setVolume(x.getTotvolume()==null?BigDecimal.ZERO:x.getTotvolume());
                    backDVO.setAcVolume(x.getTotvolume()==null?BigDecimal.ZERO:x.getTotvolume());
                    backDVO.setWayBillNo(billHDO.getShipBillNo());
                    backDVO.setPackBy(x.getCreateby());
                    backDVO.setPackDate(x.getConfirmdate()==null?null:DateUtils.format(x.getConfirmdate(),"yyyy-MM-dd HH:mm:ss"));
                    backDVO.setQty(x.getTotqty());
                    backDVO.setPcs(x.getTotpcs());
                    backDVO.setAssembleNum(x.getTotboxnum());
                    backDVO.setLength(BigDecimal.ZERO);
                    backDVO.setWide(BigDecimal.ZERO);
                    backDVO.setHigh(BigDecimal.ZERO);
                    detailList.add(backDVO);
                });
                packgeBackHVO.setPackgelist(detailList);
                resultList.add(packgeBackHVO);
            }
            try {
//                if(StringUtils.isEmpty(omsPackingBack)){
//                    throw new BizException("请求路径配置为空");
//                }
                //System.out.println(JSON.toJSONString(resultList));
                log.info("拼箱回传====>"+JSON.toJSONString(resultList));
                AskIntegrationVo vo = new AskIntegrationVo();
                vo.setIntegrationCode("omsPackingBack");
                vo.setParam(resultList);
                RestMessage<?> msg = invClient.askIntegration(vo);
                String[] upBillIds = resultList.stream().map(x -> x.getBillId()).distinct().toArray(String[]::new);
                Criteria crt = Criteria.forClass(OmsPackingData.class);
                crt.restrictionBuilder().in("billid",upBillIds);
                crt.buildRestriction();
                if (msg.isSuccess()){
                    //更新回传记录表为成功
                    omsPackingDataMapper.updateMapByCriteria(MapUtils.put("tmsFlag","1").getMap(),crt);
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}
