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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.prolog.cs.biz.outbound.dao.*;
import com.prolog.cs.biz.outbound.model.OmsDoBillHDO;
import com.prolog.cs.biz.outbound.model.OutcomingRecordD;
import com.prolog.cs.biz.outbound.model.OutcomingRecordH;
import com.prolog.cs.biz.outbound.model.SaleRedRecord;
import com.prolog.cs.biz.outbound.model.dto.OutcomingRecordHDto;
import com.prolog.cs.biz.outbound.model.dto.RedDTO;
import com.prolog.cs.biz.outbound.model.entity.OmsDoBillDDO;
import com.prolog.cs.biz.outbound.service.RedService;
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.data.exchange.client.ExchangeSender;
import com.prolog.framework.authority.core.dto.UserDTO;
import com.prolog.framework.authority.user.UserTemplate;
import com.prolog.framework.bz.core.model.ModelUtils;
import com.prolog.framework.common.message.RestMessage;
import com.prolog.framework.core.exception.BizException;
import com.prolog.framework.core.restriction.Criteria;
import com.prolog.framework.core.restriction.Restrictions;
import com.prolog.framework.utils.AssertUtils;
import com.prolog.framework.utils.MapUtils;
import com.prolog.framework.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.*;
import java.util.stream.Collectors;

@Service
public class RedServiceImpl implements RedService {
    @Autowired
    private OmsDoBillHMapper omsDoBillHMapper;

    @Autowired
    private OmsDoBillDMapper omsDoBillDMapper;

    @Autowired
    private SaleRedRecordMapper saleRedRecordMapper;

    @Autowired
    private OutcomingRecordHMapper outcomingRecordHMapper;

    @Autowired
    private OutcomingRecordDMapper outcomingRecordDMapper;

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

    @Autowired
    private PickTaskServiceImpl pickTaskServiceImpl;

    @Autowired
    private UserTemplate userTemplate;

    @Autowired
    private ExchangeSender exchangeSender;

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

    private static Logger log = LoggerFactory.getLogger(RedServiceImpl.class);

    @Override
    @Transactional
    public RestMessage<Boolean> makeOmsBillRed(RedDTO omsBill) {
        String omsBillId = omsBill.getBillId();
        OmsDoBillHDO omsDoBillHDO = omsDoBillHMapper.findById(omsBillId, OmsDoBillHDO.class);
        if (omsDoBillHDO == null) {
            throw new BizException("找不到对应的oms单据");
        }
        if (Objects.equals("1", omsDoBillHDO.getIsCancelled())) {
            throw new BizException("单据已经被整单红冲，不能再次红冲");
        }

        String redReason = omsBill.getRedReason();
        Map<String, Object> isCancelled = MapUtils.
                put("isCancelled", 1).put("partlyRed", null).
                put("redReason", redReason).getMap();
        omsDoBillHMapper.updateMapById(omsBillId, isCancelled, OmsDoBillHDO.class);
        List<OmsDoBillDDO> omsDoBillDDOS = omsDoBillDMapper.findByMap(MapUtils.put("billid", omsDoBillHDO.getBillid()).getMap(), OmsDoBillDDO.class);

        for (OmsDoBillDDO omsDoBillDDO : omsDoBillDDOS) {
            SaleRedRecord saleRedRecord = new SaleRedRecord();
            saleRedRecord.setSrcCode(omsDoBillHDO.getBillno());
            saleRedRecord.setSrcId(omsBillId);
            saleRedRecord.setReason(redReason);
            // 原单红冲
            saleRedRecord.setType(3);
            saleRedRecord.setSrcLineId(omsDoBillDDO.getLineid());
            saleRedRecord.setItemId(omsDoBillDDO.getItemid());
            saleRedRecord.setQty(omsDoBillDDO.getItemQty());
            saleRedRecord.setWarehouseId(omsDoBillDDO.getBranchid());
            UserDTO userDTO = userTemplate.getUserDTO();
            ModelUtils.setBaseInfo(saleRedRecord, ModelUtils.OpType.INSERT, userDTO);
            saleRedRecordMapper.save(saleRedRecord);
        }

        // 保存outcomming表,并回传OMS
        List<String> omsBillIds = new ArrayList<>();
        omsBillIds.add(omsBillId);
        String[] ids = new String[]{omsBillId};
        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);

        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();
        }

        return RestMessage.doSuccess(Boolean.TRUE);
    }

    @Override
    public RestMessage<Boolean> makeOmsBillItemRed(RedDTO redDTO) {
        String omsBillId = redDTO.getBillId();
        String itemId = redDTO.getItemId();
        BigDecimal qty = redDTO.getQty();
        String redReason = redDTO.getRedReason();
        String billDId = redDTO.getBillDId();
        AssertUtils.isNotNull(omsBillId, itemId, redReason, billDId);
        OmsDoBillHDO omsDoBillHDO = omsDoBillHMapper.findById(omsBillId, OmsDoBillHDO.class);
        if (omsDoBillHDO == null) {
            throw new BizException("找不到对应的oms单据");
        }
        if (Objects.equals("1", omsDoBillHDO.getIsCancelled())) {
            throw new BizException("单据已经被整单红冲，不能再次红冲");
        }
        Map<String, Object> map = MapUtils.put("lineid", billDId).put("billid", omsBillId).getMap();
        List<OmsDoBillDDO> omsDoBillDDOS = omsDoBillDMapper.findByMap(map, OmsDoBillDDO.class);
        if (omsDoBillDDOS.size() != 1) {
            throw new BizException("找不到对应的订单明细");
        }

        OmsDoBillDDO omsDoBillDDO = omsDoBillDDOS.get(0);
        if (omsDoBillDDO != null && omsDoBillDDO.getItemQty() != null) {
            if (qty.compareTo(omsDoBillDDO.getItemQty()) > 0) {
                throw new BizException("红冲数量不能大于订单数量");
            }
        }

        List<SaleRedRecord> list = saleRedRecordMapper.findByMap(MapUtils.put("srcLineId",billDId).getMap(),SaleRedRecord.class);
        if (list.size()>0) {
            BigDecimal redQty = BigDecimal.ZERO;
            for (SaleRedRecord saleRedRecord : list) {
                redQty = redQty.add(saleRedRecord.getQty());
            }
            if (redQty.add(qty).compareTo(omsDoBillDDO.getItemQty())>0)
                throw new BizException("红冲数量不能大于订单数量");
        }

        SaleRedRecord saleRedRecord = new SaleRedRecord();
        saleRedRecord.setSrcLineId(billDId);
        saleRedRecord.setSrcId(omsBillId);
        saleRedRecord.setSrcCode(omsDoBillHDO.getBillno());
        saleRedRecord.setItemId(itemId);
        saleRedRecord.setQty(qty);
        saleRedRecord.setReason(redReason);
        saleRedRecord.setType(5);
        saleRedRecord.setWarehouseId(omsDoBillHDO.getBranchid());
        UserDTO userDTO = new UserDTO();
        userDTO.setUsername(redDTO.getUserName());
        userDTO.setId(redDTO.getUserId());
        ModelUtils.setBaseInfo(saleRedRecord, ModelUtils.OpType.INSERT, userDTO);
        saleRedRecordMapper.save(saleRedRecord);

        long wholeBillMakeRed = saleRedRecordMapper.isWholeBillMakeRed(omsBillId);
        if (wholeBillMakeRed == 0) {
            // 该sql等于0标识整单红冲
            log.info("整单已经被红冲");
            Map<String, Object> isCancelled = MapUtils.
                    put("isCancelled", 1).put("partlyRed", null).
                    put("redReason", redReason).getMap();
            omsDoBillHMapper.updateMapById(omsBillId, isCancelled, OmsDoBillHDO.class);

            // 保存outcomming表,并回传OMS
            List<String> omsBillIds = new ArrayList<>();
            omsBillIds.add(omsBillId);
            String[] ids = new String[]{omsBillId};
            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);

            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();
            }
        } else {
            Map<String, Object> partlyRed = MapUtils.put("partlyRed", 1).getMap();
            omsDoBillHMapper.updateMapById(omsBillId, partlyRed, OmsDoBillHDO.class);
        }
        return RestMessage.doSuccess(Boolean.TRUE);
    }

    @Override
    public RestMessage<List<SaleRedRecord>> omsRedRecordQuery(String billId, String lineBillId) {
        List<SaleRedRecord> redRecords = saleRedRecordMapper.findByMap(MapUtils.
                        put("srcId", billId).
                        put("srcLineId", lineBillId).
                        getMap(),
                SaleRedRecord.class);
        return RestMessage.doSuccess(redRecords);
    }

    @Override
    public BigDecimal getOmsRedQty(RedDTO redDTO) {

        String billId = redDTO.getBillId();
        String itemId = redDTO.getItemId();
        String billDId = redDTO.getBillDId();
        List<SaleRedRecord> redRecords = saleRedRecordMapper.findByMap(MapUtils.
                        put("billId", billId).
                        put("billDId", billDId).
                        put("itemId", itemId).
                        getMap(),
                SaleRedRecord.class);
        BigDecimal totalQty = redRecords.stream().map(SaleRedRecord::getQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        return totalQty;

    }

    @Override
    public BigDecimal getOmsRedQty(String omsBillId, String omsBillLineId, String itemId) {

        List<SaleRedRecord> redRecords = saleRedRecordMapper.findByMap(MapUtils.
                        put("srcId", omsBillId).
                        put("srcLineId", omsBillLineId).
                        put("itemId", itemId).
                        getMap(),
                SaleRedRecord.class);
        BigDecimal totalQty = redRecords.stream().map(SaleRedRecord::getQty).filter(x -> x != null)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        return totalQty;

    }
}
