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

import cn.hutool.core.collection.CollectionUtil;
import com.codingapi.tx.annotation.TxTransaction;
import com.github.pagehelper.PageHelper;
import com.prolog.cs.basic.item.model.vo.ItemMstVO2;
import com.prolog.cs.biz.outbound.dao.*;
import com.prolog.cs.biz.outbound.model.OmsDoBillHDO;
import com.prolog.cs.biz.outbound.model.dto.*;
import com.prolog.cs.biz.outbound.model.entity.OmsDoBillDDO;
import com.prolog.cs.biz.outbound.model.vo.CargoOwnerChangeVO;
import com.prolog.cs.biz.outbound.resource.InventoryResource;
import com.prolog.cs.biz.outbound.service.*;
import com.prolog.cs.biz.outbound.service.strategy.STRATEGY_CODE;
import com.prolog.cs.biz.outbound.service.strategy.StrategySelector;
import com.prolog.cs.biz.outbound.service.strategy.handles.IStrategyHandle;
import com.prolog.cs.biz.outbound.utils.ItemUtils;
import com.prolog.cs.data.exchange.client.ExchangeSender;
import com.prolog.framework.authority.core.dto.UserDTO;
import com.prolog.framework.authority.user.UserTemplate;
import com.prolog.framework.common.message.RestMessage;
import com.prolog.framework.core.exception.BizException;
import com.prolog.framework.core.exception.PrologException;
import com.prolog.framework.core.pojo.Page;
import com.prolog.framework.dao.util.PageUtils;
import com.prolog.framework.lock.DistributedLock;
import com.prolog.framework.utils.AssertUtils;
import com.prolog.framework.utils.MapUtils;
import com.prolog.framework.utils.StringUtils;
import com.prolog.function.annotation.Flow;
import com.prolog.upcloud.base.inventory.vo.InvStockCheckOut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class WavesSpecialServiceImpl implements WavesSpecialService {

    private Logger logger = LoggerFactory.getLogger(WavesSpecialServiceImpl.class);

    @Autowired
    private WavesService wavesService;

    @Autowired
    private WaveDistributeService distribute;

    @Autowired
    private UserTemplate userTemplate;

    @Autowired
    private OmsDoBillHMapper omsDoBillHMapper;

    @Autowired
    private WaveBillMapper billMapper;

    @Autowired
    private PickTaskHMapper pickTaskHMapper;

    @Autowired
    private InventoryResource invClient;

    @Autowired
    private BarcodeHMapper barcodeHMapper;

    @Autowired
    private ExchangeSender exchangeSender;

    @Autowired
    protected DistributedLock distributedLock;

    @Autowired
    private WorkStageServiceImpl stageService;

    @Autowired
    private PickTaskService pickTaskService;

    // 业务参数配置内/外复核回传ERP by Huanglh 20220112
    @Autowired
    private StrategySelector strategySelector;

    @Autowired
    private OmsDoBillDMapper omsDoBillDMapper;

    @Autowired
    private RedService redService;

    @Override
    public List<OmsDoBillDDO> getBillDByBillId(ItemQueryDTO itemQueryDTO) {
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        Map<String, Object> map = new HashMap<>();
        map.put("EnterpriseId", enterpriseId);
        map.put("billid", itemQueryDTO.getBillid());
        if (!StringUtils.isBlank(itemQueryDTO.getItemname())) {
            map.put("itemname", itemQueryDTO.getItemname());
        }
        if (!StringUtils.isBlank(itemQueryDTO.getItemname())) {
            map.put("itemcode", itemQueryDTO.getItemcode());
        }
        List<OmsDoBillDDO> list = omsDoBillDMapper.findByMap(map, OmsDoBillDDO.class);
        if (CollectionUtil.isEmpty(list)) {
            return list;
        }
        Set<String> itemIds = list.stream().map(OmsDoBillDDO::getItemid).collect(Collectors.toSet());
        ItemUtils itemUtils = new ItemUtils(itemIds);
        for (OmsDoBillDDO x : list) {
            String itemid = x.getItemid();
            String lineid = x.getLineid();
            String billid = itemQueryDTO.getBillid();
            BigDecimal omsRedQty = redService.getOmsRedQty(billid, lineid, itemid);
            x.setItemQty(x.getItemQty().subtract(omsRedQty));
            x.setPieceQty(x.getItemQty());
            ItemMstVO2 mstVO2 = itemUtils.getByItemId(itemid);
            x.setIsCaseOrPiece(mstVO2.getIsCaseOrPiece());
            x.setBillDId(x.getLineid());
        }

        return list;
    }

    @Override
    @Transactional
    public void wavesCreateAndSend(WavesCreateDTO wavesCreateVO) {
        // 标记需要校验指定库位数量
        wavesCreateVO.setIsSpecial("Y");
        // 波次创建
        String waveId = wavesService.wavesCreate(wavesCreateVO)[0];
        // 波次下发
        distribute.distributeWave(waveId,null,"1");
    }

    /**
     *
     * @param billQueryDTO
     * @return
     */
    @Override
    public Page<OmsDoBillHDO> getSpecialOmsBillList(BillQueryDTO billQueryDTO) {
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        PageHelper.startPage(billQueryDTO.getPageNum(), billQueryDTO.getPageSize());
        List<OmsDoBillHDO> omsBill = omsDoBillHMapper.getSpecialOmsBill(billQueryDTO, enterpriseId);
        return PageUtils.getPage(omsBill);
    }

    /**
     * 代管/待检 出库确认
     *
     * @param billNoList
     * @param operatorCode
     * @param warehouseId
     */
    @Flow(name = "特殊出库", category = "出库/波次管理/特殊出库", index = 6, description = "根据入参调用库存服务扣减库存,回传ERP,写入表数据OUTCOMING_RECORD_H,OUTCOMING_RECORD_D")
    @Override
    @Transactional
    @TxTransaction
    public void specialBillConfirm(List<String> billNoList, String operatorCode, String warehouseId) {
        AssertUtils.isNotEmpty(billNoList, "订单编号不能为空");
        AssertUtils.isNotBlank(warehouseId, "仓库id不能为空");
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        if (StringUtils.isBlank(operatorCode))
            operatorCode = userDTO.getUserBizModel().getEmployeeNo();
        try {
            String finalOperatorCode = operatorCode;
            distributedLock.multiLock(billNoList.toArray(new String[0]), () -> {
                Date date = new Date();
                List<String> omsBillIds = new ArrayList<>();
                for (String billNo : billNoList) {
                    List<OmsDoBillHDO> list = omsDoBillHMapper.findByMap(MapUtils.put("billno", billNo).put("BRANCHID", warehouseId).put("pEnterpriseid", enterpriseId).getMap(), OmsDoBillHDO.class);
                    OmsDoBillHDO billh = list.get(0);
                    if (billh.getStatus().equals("10"))
                        throw new PrologException("该订单还未创建波次");
                    if (billh.getStatus().equals("30"))
                        throw new PrologException("该订单已确认，请勿重复操作");
                    omsDoBillHMapper.updateMapById(billh.getBillid(), MapUtils.put("status", "30").put("attrStr1", finalOperatorCode).put("attrDte1", date).getMap(), OmsDoBillHDO.class);
                    List<String> billIds = barcodeHMapper.getOmsBillIds(billNo, enterpriseId);
                    if (billIds.size() > 0) {
                        omsBillIds.addAll(billIds);
                    }
                }
                //扣减库存，回传erp
                this.invStockConfirm(billNoList, omsBillIds, warehouseId);
                return true;
            });
        } catch (Exception e) {
            throw new PrologException("代管/待检出库确认错误" + e.getMessage());
        }
    }

    /**
     * 查询代管/待检出库订单商品明细
     * @param srcCode
     * @param warehouseId
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public Page<PickTaskDDTO> getSpecialBillDList(String srcCode, String warehouseId, Integer pageNum, Integer pageSize) {
        AssertUtils.isNotBlank(srcCode,"订单编号不能为空");
        AssertUtils.isNotBlank(warehouseId,"仓库id不能为空");
        PageHelper.startPage(pageNum, pageSize);
        List<PickTaskDDTO> list = pickTaskHMapper.getSpecialBillDList(srcCode, warehouseId);
        return PageUtils.getPage(list);
    }

    /**
     * 货主转换
     */
    @Flow(name = "货主转换", category = "出库/波次管理/特殊出库货主转换", index = 7, description = "根据WAVEID保存商品预占,并自动生成出库数据，组包，生成拣选任务（特殊订单），扣减库存，回传ERP")
    @Override
    @Transactional
    @TxTransaction
    public void cargoOwnerChange(List<CargoOwnerChangeVO> list) {
        UserDTO userDTO = userTemplate.getUserDTO();
        for (CargoOwnerChangeVO vo : list) {
            WavesCreateDTO wavesCreateVO = new WavesCreateDTO();
            wavesCreateVO.setBillType("1");
            wavesCreateVO.setWarehouseId(vo.getWarehouseId());
            List<String> billIdList = new ArrayList<>();
            billIdList.add(vo.getOmsBillId());
            wavesCreateVO.setBillIdList(billIdList);
            //1.波次创建
            String waveId = wavesService.wavesCreate(wavesCreateVO)[0];
            //2.波次下发
            distribute.distributeWave(waveId,null, "1");
            //3.保存商品预占,并自动生成出库数据
            stageService.handle2(waveId, vo, userDTO);
        }
    }

    /**
     *
     * @param billIds
     * @return
     */
    @Override
    public List<BillHDTO> getOmsBillDate(List<String> billIds) {
        List<BillHDTO> billHList = new ArrayList<>();
        for (String billId : billIds) {
            OmsDoBillHDO omsDoBillHDO = omsDoBillHMapper.findById(billId,OmsDoBillHDO.class);
            if(omsDoBillHDO!=null){
                BillHDTO billHDTO = new BillHDTO();
                billHDTO.setBillId(billId);
                billHDTO.setBranchId(omsDoBillHDO.getBranchid());
                billHDTO.setEnterpriseId(omsDoBillHDO.getEnterpriseId());
                billHDTO.setConsignorId(omsDoBillHDO.getConsignorid());
                List<BillDDTO> billDList = omsDoBillHMapper.getOmsBillDList(billId,omsDoBillHDO.getBranchid());
                billHDTO.setBillDList(billDList);
                billHList.add(billHDTO);
            }
        }
        return billHList;
    }

    /**
     * 扣减库存,回传ERP
     * @param srcCodes
     * @param omsBillIds
     * @param warehouseId
     */
    private void invStockConfirm(List<String> srcCodes,List<String> omsBillIds, String warehouseId) {
        InvStockCheckOut invStockCheck = new InvStockCheckOut();
        List<String> billdIdList = billMapper.getBillDIdList(srcCodes,null,warehouseId);
        if(billdIdList.size()>0){
            invStockCheck.setLineBillIds(billdIdList.toArray(new String[billdIdList.size()]));
            RestMessage restMessage = invClient.outStockCheck(invStockCheck);
            if (!restMessage.isSuccess()) {
                throw new BizException("扣减库存失败: " + restMessage.getMessage());
            }
        }

        // ERP回传方式写中间表，通过mq立刻通知oms处理，使用 PostBackErpHandle by Huanglh 20220112
        /*for (String omsBillId : omsBillIds) {
            EtlMessage etlMessage = new EtlMessage();
            etlMessage.setId(omsBillId);
            etlMessage.setEtlType(EtlTypeConstants.out_do_w2o);
            try {
                exchangeSender.send(etlMessage);
            } catch (Exception e) {
                throw new BizException("外复核确认，回传ERP，rabbitmq发送消息失败！");
            }
        }*/
        // 只需要需要判断一个业务配置参数
        IStrategyHandle strategyHandle = strategySelector.selectHandle(Arrays.asList(
          STRATEGY_CODE.POST_BACK_ERP__MQ__ON), warehouseId, "do");
        strategyHandle.execute(omsBillIds);
    }

}
