package com.sunda.spmswms.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sunda.spmscommon.ResponseResult;
import com.sunda.spmscommon.entity.ZSapOrgClient;
import com.sunda.spmscommon.feign.IFeignServiceCommon;
import com.sunda.spmscommon.mapper.ZSapOrgClientMapper;
import com.sunda.spmswms.entity.SapBoxNote;
import com.sunda.spmswms.entity.SapBoxNoteDtl;
import com.sunda.spmswms.entity.WhsInventoryInfo;
import com.sunda.spmswms.entity.WhsStorageInventory;
import com.sunda.spmswms.mapper.SapRepackageMapper;
import com.sunda.spmswms.service.*;
import feign.FeignException;
import lombok.extern.slf4j.Slf4j;

import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.util.*;

/**
 * @program: spms
 * @description:
 * @author: Wayne Wu
 * @create: 2021-10-21 11:10
 **/

@Slf4j
@Service
public class SapRepackageImpl implements ISapRepackage {

    @Autowired
    ISapBoxNoteService iSapBoxNoteService;

    @Autowired
    ISapBoxNoteDtlService iSapBoxNoteDtlService;

    @Autowired
    IWhsStorageInventoryService iWhsStorageInventoryService;

    @Autowired
    IWhsInventoryInfoService iWhsInventoryInfoService;

    @Autowired
    IWhsOperateLogService iWhsOperateLogService;

    @Autowired
    IFeignServiceCommon iFeignServiceCommon;

    @Autowired
    ISapDeliveryNoteLogService iSapDeliveryNoteLogService;

    @Autowired
    SapRepackageMapper sapRepackageMapper;
    
    @Autowired
    ZSapOrgClientMapper zSapOrgClientMapper;

    /***
     {
     "boxNote": "BJ-10218800042-0305",
     "werks": "CN01",
     "whsLocationCode": "1061",
     "boxNoteDtl": [{
     "boxNote": "BJ-10218800042-0305",
     "item": 1,
     "domesticQtyReceived": 6
     }],
     "newBoxNoteDtl": [{
     "item": 1,
     "domesticQtyReceived": 2
     }]
     }
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ResponseResult sapRepackageBox(JSONObject doc, String userId) throws Exception{
//        try {
            ResponseResult checkResult = checkData(doc);
            if (checkResult.getCode() != 200){
                return checkResult;
            }
            String boxNote = doc.getString("boxNote");
            String werks = doc.getString("werks");
            String whsLocationCode = doc.getString("whsLocationCode");
            JSONArray boxNoteDtl = doc.getJSONArray("boxNoteDtl");
            JSONArray newBoxNoteDtl = doc.getJSONArray("newBoxNoteDtl");
            String newBoxNote = generateBoxNote(whsLocationCode);

            SapBoxNote sapBoxNote = iSapBoxNoteService.getByBoxNote(boxNote);

            WhsStorageInventory whsStorageInventory = iWhsStorageInventoryService.getBoxNoteStorage(boxNote);

            /** 拼接请求SAP，请求SAP */
            JSONObject dataToSap = repackageToSap(boxNote, boxNoteDtl, newBoxNote, newBoxNoteDtl);
            // 根据工厂查询SAP Clinet
            List<ZSapOrgClient> clinetList = zSapOrgClientMapper.selectList(new QueryWrapper<ZSapOrgClient>().eq("WERKS", werks));
            if (CollectionUtils.isNotEmpty(clinetList)) {
            	JSONObject obj = dataToSap.getJSONObject("REQUEST").getJSONObject("ESB_ATTRS");
            	obj.put("Target_ID", "SAP-"+clinetList.get(0).getZmandt());
            } else {
            	throw new Exception("工厂："+werks+"未找到对应的SAP Clinet");
            }
            JSONObject message = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSap));
            log.info("\n=====dataToSap======\n" + dataToSap + "\n=====sapReturnedMessage======\n" + message);

            if ("S".equals(message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA").getString("O_TYPE"))){
                iSapDeliveryNoteLogService.insertSapRequestRecord(boxNote, userId,"拆箱成功，新箱码：" + newBoxNote, message.toJSONString(), dataToSap.toJSONString());
                iSapDeliveryNoteLogService.insertSapRequestRecord(newBoxNote, userId,"拆箱成功，原箱码：" + boxNote, message.toJSONString(), dataToSap.toJSONString());

                /** 1.修改原箱箱码表头信息 */
                //sapBoxNote.setRemarks(StringUtils.isEmpty(sapBoxNote.getRemarks()) ? "拆出新箱:" + newBoxNote : ";拆出新箱:" + newBoxNote);

                /** 2.修改原箱箱码明细信息 */
                for (int i = 0; i < boxNoteDtl.size(); i++){
                    int item = boxNoteDtl.getJSONObject(i).getInteger("item");
                    double domesticQtyReceived = boxNoteDtl.getJSONObject(i).getDoubleValue("domesticQtyReceived");
                    iSapBoxNoteDtlService.updateSapBoxNoteDtlBeta(boxNote, item, domesticQtyReceived, newBoxNote);
                }

                /** 3.新增新箱码表头信息 */
                sapBoxNote.setBoxNote(newBoxNote);
                sapBoxNote.setParentBoxNote(boxNote);
                iSapBoxNoteService.save(sapBoxNote);

                /** 4.新增新箱码明细信息 */
                for (int j = 0; j < newBoxNoteDtl.size(); j++){
                    int item = newBoxNoteDtl.getJSONObject(j).getInteger("item");
                    double domesticQtyReceived = newBoxNoteDtl.getJSONObject(j).getDoubleValue("domesticQtyReceived");
                    QueryWrapper<SapBoxNoteDtl> queryWrapper = new QueryWrapper<SapBoxNoteDtl>().eq("BOX_NOTE", boxNote).eq("ITEM", item);
                    SapBoxNoteDtl sapBoxNoteDtl = iSapBoxNoteDtlService.getOne(queryWrapper);
                    sapBoxNoteDtl.setBoxNote(newBoxNote);
                    /** 拆出的新箱码明细，数量(应收数量) QUANTITY、国内收数量 DOMESTIC_QTY_RECEIVABLE 字段值都给 0 ————20211026 */
                    sapBoxNoteDtl.setQuantity(0.0);
                    sapBoxNoteDtl.setDomesticQtyReceivable(0.0);
                    sapBoxNoteDtl.setDomesticQtyReceived(domesticQtyReceived);
                    iSapBoxNoteDtlService.save(sapBoxNoteDtl);
                }

                /** 5.新增储位库存、记录储位库存增加日志 */
                String uuidStorage = whsStorageInventory.getUuid();
                iWhsStorageInventoryService.updateStorageInvX(uuidStorage, newBoxNote, 1, "add");
                iWhsOperateLogService.insertWhsOperateLog("2", uuidStorage, "", newBoxNote, 1, "2", newBoxNote,
                        "拆箱增加储位库存", userId, "拆箱增加储位库存", werks, whsLocationCode, "");


                /** 6.新增仓库库存、记录仓库库存增加日志 */
                iWhsInventoryInfoService.updateWhsInventoryX(werks, whsLocationCode, newBoxNote, 1, "add", userId);
                iWhsOperateLogService.insertWhsOperateLog("1", "", "", newBoxNote, 1, "1", newBoxNote,
                        "拆箱增加仓库库存", userId, "拆箱增加仓库库存", werks, whsLocationCode, "");

                return ResponseResult.success()
                        .add("newBoxNote", iSapBoxNoteService.getByBoxNote(newBoxNote))
                        .add("newBoxNoteDtl", iSapBoxNoteDtlService.getSapBoxNoteDtlList(newBoxNote))
                        .add("boxNoteDtl", iSapBoxNoteDtlService.getSapBoxNoteDtlList(boxNote))
                        .add("dataToSap", dataToSap)
                        .add("sapReturnedMessage", message);
            } else {
                iSapDeliveryNoteLogService.insertSapRequestRecord(boxNote, userId,"拆箱失败", message.toJSONString(), dataToSap.toJSONString());
                return ResponseResult.error()
                        .add("dataToSap", dataToSap)
                        .add("sapReturnedMessage", message);
            }
//        }catch (FeignException feignException){
//            feignException.printStackTrace();
//            return ResponseResult.error("请求SAP失败 FeignException").add("error", feignException.getMessage());
//        }catch (Exception e){
//            e.printStackTrace();
//            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
//            return ResponseResult.error("提交SAP失败 Exception").add("error", e.getMessage());
//        }
    }

    /**
     {
     "boxNote": "BJ-10218800042-0305",
     "werks": "CN01",
     "whsLocationCode": "1061",
     "boxNoteDtl": [{
     "boxNote": "BJ-10218800042-0305",
     "item": 1,
     "domesticQtyReceived": 6
     }],
     "newBoxNoteDtl": [{
     "item": 1,
     "domesticQtyReceived": 2
     }]
     }
     * @param doc
     * @return
     */
    ResponseResult checkData(JSONObject doc){
        if (!doc.containsKey("boxNote") || !doc.containsKey("boxNoteDtl") || !doc.containsKey("newBoxNoteDtl")){
            return ResponseResult.error("请求参数错误请重试");
        }
        String boxNote = doc.getString("boxNote");
        String werks = doc.getString("werks");
        String whsLocationCode = doc.getString("whsLocationCode");
        JSONArray boxNoteDtl = doc.getJSONArray("boxNoteDtl");
        JSONArray newBoxNoteDtl = doc.getJSONArray("newBoxNoteDtl");

        if (StringUtils.isEmpty(boxNote) || StringUtils.isEmpty(werks) || StringUtils.isEmpty(whsLocationCode)
                || boxNoteDtl.size() == 0 || newBoxNoteDtl.size() == 0 || boxNoteDtl.size() != newBoxNoteDtl.size()){
            return ResponseResult.error("请求参数错误请重试");
        }
        WhsInventoryInfo whsInventoryInfo = iWhsInventoryInfoService.getWhsInventoryInfoByBoxNote(boxNote, werks, whsLocationCode);
        if (whsInventoryInfo == null){
            return ResponseResult.error("请求箱码仓库库存不存在，操作终止");
        }
        WhsStorageInventory whsStorageInventory = iWhsStorageInventoryService.getBoxNoteStorage(boxNote);
        if (whsStorageInventory == null){
            return ResponseResult.error("请求箱码储位库存不存在，操作终止");
        }
        for (int i = 0; i < boxNoteDtl.size(); i ++){
            JSONObject obj = boxNoteDtl.getJSONObject(i);
            String item = obj.getString("item");
            List<SapBoxNoteDtl> boxNoteDtlList = iSapBoxNoteDtlService.getBoxNoteDtlList(boxNote, item);
            if (boxNoteDtlList == null){
                return ResponseResult.error("请求箱码明细数据不存在");
            }
            if (boxNoteDtlList.size() > 1){
                return ResponseResult.error("请求箱码明细数据不正确");
            }
        }
        return ResponseResult.success();
    }

    JSONObject repackageToSap(String boxNote, JSONArray boxNoteDtl, String newBoxNote, JSONArray newBoxNoteDtl){
        JSONObject doc = new JSONObject();
        JSONObject REQUEST = new JSONObject();
        JSONObject ESB_ATTRS = new JSONObject();
        JSONObject REQUEST_DATA = new JSONObject();
        ESB_ATTRS.put("App_ID", "SPMS");
        ESB_ATTRS.put("Application_ID", "00020000000002");
        ESB_ATTRS.put("Transaction_ID", UUID.randomUUID().toString());
        JSONObject tables = new JSONObject();
        List<Map<String, Object>> it_head = new ArrayList<>();
        Map<String, Object> Head = sapRepackageMapper.getHeadToSap(boxNote);
        it_head.add(Head);
        tables.put("IT_HEAD", it_head);
        JSONArray IT_XHEAD = formatItXHead(boxNote, newBoxNote);
        tables.put("IT_XHEAD", IT_XHEAD);
        List<Map<String, Object>> IT_ITME = formatItItem(boxNote, boxNoteDtl, newBoxNote, newBoxNoteDtl);
        tables.put("IT_ITME", IT_ITME);
        REQUEST_DATA.put("tables", tables);
        REQUEST_DATA.put("Operation", "Z_SPMS_SETBOXCODE");
        REQUEST_DATA.put("Type", "SETBOXCODE");

        REQUEST.put("ESB_ATTRS", ESB_ATTRS);
        REQUEST.put("REQUEST_DATA", REQUEST_DATA);

        doc.put("REQUEST", REQUEST);
        return doc;
    }

    /** 转换箱码信息传输SAP结构 */
    JSONArray formatItXHead(String boxNote, String newBoxNote){
        JSONArray array = new JSONArray();
        Map<String, Object> boxNoteToSap = sapRepackageMapper.boxNoteToSap(boxNote);
        // 查询箱码储位的工厂跟仓库
        Map<String, String> bukrsByBoxNote = this.sapRepackageMapper.selectBukrsByBoxNote(boxNote);
        boxNoteToSap.put("WERKS_CF", bukrsByBoxNote != null ? bukrsByBoxNote.get("WERKS") : "");
        boxNoteToSap.put("LGORT_CF", bukrsByBoxNote != null ? bukrsByBoxNote.get("WHS_LOCATION_CODE") : "");
        // 箱码状态：固定值-2
        boxNoteToSap.put("STATSU_PKCODE", "2");
        // 箱码类型：固定值-1
        boxNoteToSap.put("CODE_TYPE", "1");
        Map<String, Object> newBoxNoteToSap = new HashMap<>();
        array.add(boxNoteToSap);
        boxNoteToSap.forEach((key, value) -> {
            if ("PACKAGE_CODE".equals(key)){
                newBoxNoteToSap.put(key, newBoxNote);
            } else {
                newBoxNoteToSap.put(key, value);
            }
        });
        array.add(newBoxNoteToSap);
        return array;
    }

    /** 转换箱码明细信息传输SAP结构 */
    List<Map<String, Object>> formatItItem(String boxNote, JSONArray boxNoteDtl, String newBoxNote, JSONArray newBoxNoteDtl){
        List<Map<String, Object>> mapList = new ArrayList<>();
        List<SapBoxNoteDtl> sapBoxNoteDtlList = iSapBoxNoteDtlService.getSapBoxNoteDtlList(boxNote);
        List<SapBoxNoteDtl> dataToSap = new ArrayList<>();
        // 根据箱码查询箱码储位库存所在工厂，再根据工厂查询所属公司代码：存在拆箱后的箱码查不到公司代码，所以用拆箱前的箱码查询
        Map<String, String> bukrsByBoxNote = this.sapRepackageMapper.selectBukrsByBoxNote(boxNote);
        for (SapBoxNoteDtl sapBoxNoteDtl : sapBoxNoteDtlList){
            String item = sapBoxNoteDtl.getItem().toString();
            for (int i = 0; i < boxNoteDtl.size(); i ++){
                JSONObject doc = boxNoteDtl.getJSONObject(i);
                double domesticQtyReceived = doc.getDoubleValue("domesticQtyReceived");
                if (item.equals(doc.getString("item"))){
                    sapBoxNoteDtl.setDomesticQtyReceived(domesticQtyReceived);
                }
            }
            // 原箱更新后的信息结构加到请求SAP中
            Map<String, Object> map = new HashMap<>();
            map.put("PACKAGE_NO", sapBoxNoteDtl.getPackageNote());
            map.put("SERIAL", sapBoxNoteDtl.getItem().toString());
            map.put("PACKAGE_CODE", sapBoxNoteDtl.getBoxNote());
            map.put("PACKAGE_POSNR", sapBoxNoteDtl.getPackagePosnr() != null ? sapBoxNoteDtl.getPackagePosnr().toString() : "");
            map.put("MATNR", sapBoxNoteDtl.getMaterialNo() != null ? sapBoxNoteDtl.getMaterialNo().replaceAll("^(0+)", "") : "");
            map.put("SPECS", sapBoxNoteDtl.getSpecs() != null ? sapBoxNoteDtl.getSpecs() : "");
            map.put("MENGE", sapBoxNoteDtl.getQuantity() != null ? sapBoxNoteDtl.getQuantity().toString() : "0");
            map.put("MEINS", sapBoxNoteDtl.getBasicUnit());
            map.put("SRM_CONTRACT_NO", sapBoxNoteDtl.getSrmContractNo() != null ? sapBoxNoteDtl.getSrmContractNo() : "");
            map.put("EBELN", sapBoxNoteDtl.getPurchaseNo() != null ? sapBoxNoteDtl.getPurchaseNo() : "");
            map.put("EBELP", sapBoxNoteDtl.getPurchaseNoItem() != null ? sapBoxNoteDtl.getPurchaseNoItem().toString() : "");
            map.put("VBELN", sapBoxNoteDtl.getDeliveryNoteSap() != null ? sapBoxNoteDtl.getDeliveryNoteSap() : "");
            map.put("POSNR", sapBoxNoteDtl.getDeliveryNoteSapItem() != null ? sapBoxNoteDtl.getDeliveryNoteSapItem().toString() : "");
            map.put("DEMAND_NO", sapBoxNoteDtl.getDemandNo() != null ? sapBoxNoteDtl.getDemandNo() : "");
            map.put("DEMAND_POSNR", sapBoxNoteDtl.getDemandNoItem() != null ? sapBoxNoteDtl.getDemandNoItem().toString() : "");
            map.put("DEMANDER", sapBoxNoteDtl.getDemander() != null ? sapBoxNoteDtl.getDemander() : "");
            map.put("MARK", sapBoxNoteDtl.getRemark() != null ? sapBoxNoteDtl.getRemark() : "");
            map.put("BRGEW", sapBoxNoteDtl.getGrossWeight() != null ? sapBoxNoteDtl.getGrossWeight().toString() : "0");
            map.put("NTGEW", sapBoxNoteDtl.getNetWeight() != null ? sapBoxNoteDtl.getNetWeight().toString() : "0");
            map.put("GNSHSL", sapBoxNoteDtl.getDomesticQtyReceivable() != null ? sapBoxNoteDtl.getDomesticQtyReceivable().toString() : "0");
            map.put("GNSJSL", sapBoxNoteDtl.getDomesticQtyReceived() != null ? sapBoxNoteDtl.getDomesticQtyReceived().toString() : "0");
            map.put("HWSHSL", sapBoxNoteDtl.getOverseaQtyReceived() != null ? sapBoxNoteDtl.getOverseaQtyReceived().toString() : "0");
            if (bukrsByBoxNote != null) {
            	map.put("BUKRS", bukrsByBoxNote.get("BUKRS"));
            }
            mapList.add(map);
        }

        for (SapBoxNoteDtl sapBoxNoteDtl : sapBoxNoteDtlList){
            String item = sapBoxNoteDtl.getItem().toString();
            for (int j = 0; j < newBoxNoteDtl.size(); j ++){
                SapBoxNoteDtl dtl = new SapBoxNoteDtl();
                JSONObject obj = newBoxNoteDtl.getJSONObject(j);
                double domesticQtyReceived = obj.getDoubleValue("domesticQtyReceived");
                if (item.equals(obj.getString("item"))){
                	// 生成的新箱码信息结构加到请求SAP中
                	Map<String, Object> map = new HashMap<>();
                    map.put("PACKAGE_NO", sapBoxNoteDtl.getPackageNote());
                    map.put("SERIAL", sapBoxNoteDtl.getItem().toString());
                    map.put("PACKAGE_CODE", newBoxNote);
                    map.put("PACKAGE_POSNR", sapBoxNoteDtl.getPackagePosnr() != null ? sapBoxNoteDtl.getPackagePosnr().toString() : "");
                    map.put("MATNR", sapBoxNoteDtl.getMaterialNo() != null ? sapBoxNoteDtl.getMaterialNo().replaceAll("^(0+)", "") : "");
                    map.put("SPECS", sapBoxNoteDtl.getSpecs() != null ? sapBoxNoteDtl.getSpecs() : "");
                    map.put("MENGE", sapBoxNoteDtl.getQuantity() != null ? sapBoxNoteDtl.getQuantity().toString() : "0");
                    map.put("MEINS", sapBoxNoteDtl.getBasicUnit());
                    map.put("SRM_CONTRACT_NO", sapBoxNoteDtl.getSrmContractNo() != null ? sapBoxNoteDtl.getSrmContractNo() : "");
                    map.put("EBELN", sapBoxNoteDtl.getPurchaseNo() != null ? sapBoxNoteDtl.getPurchaseNo() : "");
                    map.put("EBELP", sapBoxNoteDtl.getPurchaseNoItem() != null ? sapBoxNoteDtl.getPurchaseNoItem().toString() : "");
                    map.put("VBELN", sapBoxNoteDtl.getDeliveryNoteSap() != null ? sapBoxNoteDtl.getDeliveryNoteSap() : "");
                    map.put("POSNR", sapBoxNoteDtl.getDeliveryNoteSapItem() != null ? sapBoxNoteDtl.getDeliveryNoteSapItem().toString() : "");
                    map.put("DEMAND_NO", sapBoxNoteDtl.getDemandNo() != null ? sapBoxNoteDtl.getDemandNo() : "");
                    map.put("DEMAND_POSNR", sapBoxNoteDtl.getDemandNoItem() != null ? sapBoxNoteDtl.getDemandNoItem().toString() : "");
                    map.put("DEMANDER", sapBoxNoteDtl.getDemander() != null ? sapBoxNoteDtl.getDemander() : "");
                    map.put("MARK", sapBoxNoteDtl.getRemark() != null ? sapBoxNoteDtl.getRemark() : "");
                    map.put("BRGEW", sapBoxNoteDtl.getGrossWeight() != null ? sapBoxNoteDtl.getGrossWeight().toString() : "0");
                    map.put("NTGEW", sapBoxNoteDtl.getNetWeight() != null ? sapBoxNoteDtl.getNetWeight().toString() : "0");
                    map.put("GNSHSL", domesticQtyReceived);
                    map.put("GNSJSL", domesticQtyReceived);
                    map.put("HWSHSL", "0");
                    if (bukrsByBoxNote != null) {
                    	map.put("BUKRS", bukrsByBoxNote.get("BUKRS"));
                    }
                    
                    map.put("PACKAGE_CODE2", boxNote);
                    map.put("SERIAL2", item);
                    mapList.add(map);
                }
            }
        }
        return mapList;
    }

    /** 生成新箱码 CX-10611000001-0101 */
    String generateBoxNote(String whsLocationCode){
        int getNewBoxNote = iSapBoxNoteService.getNewBoxNote();
        return "CX-" + whsLocationCode + getNewBoxNote + "-0101";
    }

    @Override
    public ResponseResult getSapBoxNoteListPage(String werks, String whsLocationCode, String boxNote, Integer pageNo, Integer pageSize) {
        ResponseResult checkResult = checkValidate(werks, whsLocationCode, pageNo, pageSize);
        if (checkResult.getCode() != 200){
            return checkResult;
        }
        pageNo = pageNo <= 0 ? 1 : pageNo;
        pageSize = pageSize <= 0 ? 20 : pageSize;
        boxNote = StringUtils.isEmpty(boxNote) ? null : boxNote;
        Page<Map<String, Object>> mapPage = new Page<>(pageNo, pageSize);
        List<Map<String, Object>> pageMaData = sapRepackageMapper.pageMaDataMap(mapPage, werks, whsLocationCode, boxNote);
        mapPage.setRecords(pageMaData);
        return ResponseResult.success().add("sapBoxNoteList", mapPage);
    }

    ResponseResult checkValidate(String werks, String whsLocationCode, Integer pageNo, Integer pageSize){
        if (StringUtils.isEmpty(werks) || StringUtils.isEmpty(whsLocationCode)){
            return ResponseResult.error("请求参数错误");
        }
        return ResponseResult.success();
    }
}


