package cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.base;

import cn.estsh.i3plus.ext.mes.pcn.api.base.IBomTakeEffectService;
import cn.estsh.i3plus.ext.mes.pcn.api.base.ISxPcnHttpService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IProduceSnExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.jx.IJxProduceSnMcRecordService;
import cn.estsh.i3plus.ext.mes.pcn.pojo.bean.*;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.BomTakeEffectModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.WmsBomTotalModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.repository.MesBomPendingPartRepository;
import cn.estsh.i3plus.ext.mes.pcn.pojo.repository.MesBomTakeEffectRecordRepository;
import cn.estsh.i3plus.ext.mes.pcn.pojo.repository.MesPartExtRepository;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtEnumUtil;
import cn.estsh.i3plus.mes.pcn.util.PcnHttpUtil;
import cn.estsh.i3plus.platform.common.convert.ConvertBean;
import cn.estsh.i3plus.platform.common.exception.ImppExceptionEnum;
import cn.estsh.i3plus.platform.common.tool.JsonUtilTool;
import cn.estsh.i3plus.platform.common.tool.TimeTool;
import cn.estsh.i3plus.platform.common.util.MesConstWords;
import cn.estsh.i3plus.pojo.base.bean.BaseResultBean;
import cn.estsh.i3plus.pojo.base.bean.DdlPackBean;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.tool.DdlPreparedPack;
import cn.estsh.i3plus.pojo.mes.bean.MesBom;
import cn.estsh.i3plus.pojo.mes.repository.MesBomRepository;
import cn.estsh.impp.framework.boot.exception.ImppExceptionBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * 文件描述
 *
 * @author xiangming.liao
 * @date 2021年03月27日 15:45
 */
@Slf4j
@Service
public class BomTakeEffectService implements IBomTakeEffectService {
    @Autowired
    private IProduceSnExtService produceSnExtService;
    @Autowired
    private ISxPcnHttpService pcnHttpService;
    @Autowired
    private MesBomRepository bomRepository;
    @Autowired
    private MesBomTakeEffectRecordRepository bomTakeEffectRecordRepository;
    @Autowired
    private MesPartExtRepository partExtRDao;
    @Autowired
    private IJxProduceSnMcRecordService jxProduceSnMcRecordService;
    @Autowired
    private MesBomPendingPartRepository bomPendingPartRepository;

    @Override
    public MesProduceSnExt queryProduceSnBySn(String serialNumber, String organizeCode) {

        MesProduceSnMcRecord produceSnMcRecordDb = jxProduceSnMcRecordService.getProduceSnMcRecordDb(organizeCode, serialNumber);

        if (produceSnMcRecordDb == null) return produceSnExtService.getProduceSnExtByProductSn(organizeCode, serialNumber);

        return produceSnExtService.getProduceSnExtByProductSn(organizeCode, produceSnMcRecordDb.getProductSn());
    }

    @Override
    public List<WmsBomTotalModel> queryWmsBomTotalByPartNo(String partNo, String organizeCode) throws IOException {
        String requestUrl = pcnHttpService.getRequestUrl(organizeCode, MesPcnExtConstWords.FIND_BY_PARTNO);
        Map<String, String> params = new HashMap<>();
        params.put(MesPcnExtConstWords.PART_NO, partNo);
        params.put(MesPcnExtConstWords.ORGANIZE_CODE, organizeCode);
        String data = PcnHttpUtil.doPost(requestUrl, params);
        BaseResultBean baseResultBean = null;
        List<WmsBomTotalModel> wmsBomTotalList = new ArrayList<>();
        if (!StringUtils.isEmpty(data)) {
            baseResultBean = JsonUtilTool.decode(data, BaseResultBean.class);
        } else {
            log.error("HTTP[{}]调用mes获取wmsBomTotal信息接口失败", requestUrl);
        }
        if (null != baseResultBean && baseResultBean.success) {
            wmsBomTotalList = (List<WmsBomTotalModel>) baseResultBean.getResultList();
        } else {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_EXIT.getCode())
                    .setErrorDetail(baseResultBean.getErrorMsg())
                    .build();
        }
        if (CollectionUtils.isEmpty(wmsBomTotalList)) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_EXIT.getCode())
                    .setErrorDetail("无法获取此bom信息")
                    .build();
        }
        return wmsBomTotalList;
    }

    @Override
    public void doEffect(BomTakeEffectModel bomTakeEffectModel){

        String organizeCode = bomTakeEffectModel.getOrganizeCode();
        String userName = bomTakeEffectModel.getUserInfo();
        String partNo = bomTakeEffectModel.getPartNo();

        BaseResultBean bomEffectResultBean = doWmsBomEffect(organizeCode, partNo);

        log.info("BOM生效 --- bomTakeEffectModel: {} --- bomEffectResultBean: {}", bomTakeEffectModel, bomEffectResultBean);

        if (null != bomEffectResultBean && bomEffectResultBean.success) {

            log.info("BOM生效 --- doEffect --- WMS-BOM生效成功!");

            List<MesBom> bomListByDb = queryOldPartBom(organizeCode, partNo);

            // 保存待BOM生效成品
            saveBomPendingPart(bomTakeEffectModel, organizeCode, bomListByDb);

            // 删除旧BOM数据
            deleteOldBom(bomListByDb);

            // 保存新Bom数据
            saveNewPartBom(bomTakeEffectModel.getWmsBomTotalModels(), userName);

            // 插入BOM生效记录表
            saveBomEffectRecord(organizeCode, userName, partNo, bomTakeEffectModel.getWorkOrderNo(), bomTakeEffectModel.getProductSn());
        }

    }

    private void deleteOldBom(List<MesBom> bomListByDb) {
        if (CollectionUtils.isEmpty(bomListByDb)) return;
        bomRepository.deleteAll(bomListByDb);
    }

    private void saveBomPendingPart(BomTakeEffectModel bomTakeEffectModel, String organizeCode, List<MesBom> bomListByDb) {

        List<String> oldItemPartNoList = getItemPartNoList(bomListByDb);

        removeSamePartByNewBom(oldItemPartNoList, bomTakeEffectModel.getWmsBomTotalModels());

        removeRecordedPart(oldItemPartNoList, organizeCode);

        saveBomPendingPart(oldItemPartNoList, bomTakeEffectModel);

        updateBomPendingPartByPartByPartNo(bomTakeEffectModel.getPartNo(), bomTakeEffectModel.getOrganizeCode(), bomTakeEffectModel.getUserInfo());

        log.info("BOM生效 --- updateBomPendingPartByPartByPartNo --- 成功!");
    }

    private List<String> getItemPartNoList(List<MesBom> bomListByDb) {
        return CollectionUtils.isEmpty(bomListByDb) ? null :
                bomListByDb.stream().map(MesBom::getItemPartNo).collect(Collectors.toList());
    }

    private void saveBomPendingPart(List<String> oldItemPartNoList, BomTakeEffectModel bomTakeEffectModel) {

        if (CollectionUtils.isEmpty(oldItemPartNoList)) return;

        List<MesBom> mesBomList = queryBomByItemPartNo(bomTakeEffectModel.getOrganizeCode(), oldItemPartNoList);

        if (CollectionUtils.isEmpty(mesBomList)) return;

        mesBomList = removeCurPartBom(bomTakeEffectModel, mesBomList);

        if (CollectionUtils.isEmpty(mesBomList)) return;

        List<MesBomPendingPart> bomPendingPartList = new ArrayList<>(mesBomList.size());

        for (MesBom mesBom : mesBomList) {
            MesBomPendingPart bomPendingPart = new MesBomPendingPart();
            BeanUtils.copyProperties(mesBom, bomPendingPart , MesPcnExtConstWords.ID, MesPcnExtConstWords.CREATE_USER, MesPcnExtConstWords.CREATE_DATE_TIME, MesPcnExtConstWords.MODIFY_USER, MesPcnExtConstWords.MODIFY_DATE_TIME);
            ConvertBean.serviceModelInitialize(bomPendingPart, bomTakeEffectModel.getUserInfo());
            bomPendingPart.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            bomPendingPart.setIsReminded(MesPcnExtEnumUtil.TRUE_OR_FALSE.FALSE.getValue());
            bomPendingPart.setIsTookEffect(MesPcnExtEnumUtil.TRUE_OR_FALSE.FALSE.getValue());
            bomPendingPartList.add(bomPendingPart);
        }

        bomPendingPartRepository.saveAll(bomPendingPartList);
    }

    private void updateBomPendingPartByPartByPartNo(String partNo, String organizeCod, String userInfo) {

        bomPendingPartRepository.updateByProperties(
                new String[]{MesPcnExtConstWords.PART_NO, "isTookEffect", MesPcnExtConstWords.ORGANIZE_CODE,
                        MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.IS_DELETED},
                new Object[]{partNo, MesPcnExtEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), organizeCod,
                        CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue()},
                new String[]{"isTookEffect", "isReminded", MesPcnExtConstWords.SYSTEM_SYNC_STATUS,
                        MesPcnExtConstWords.MODIFY_USER, MesPcnExtConstWords.MODIFY_DATE_TIME},
                new Object[]{MesPcnExtEnumUtil.TRUE_OR_FALSE.TRUE.getValue(), MesPcnExtEnumUtil.TRUE_OR_FALSE.TRUE.getValue(),
                        MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue(), userInfo, TimeTool.getNowTime(true)});

    }

    private List<MesBom> removeCurPartBom(BomTakeEffectModel bomTakeEffectModel, List<MesBom> mesBomList) {
        return mesBomList.stream().filter(o -> !o.getPartNo().equals(bomTakeEffectModel.getPartNo()))
                .collect(Collectors.toList());
    }

    private void removeRecordedPart(List<String> oldItemPartNoList, String organizeCode) {

        if (CollectionUtils.isEmpty(oldItemPartNoList)) return;

        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        packBean.addColumnQuery("isReminded", " and ( model." + "isReminded" + " = :m_" + "isReminded", MesPcnExtEnumUtil.TRUE_OR_FALSE.FALSE.getValue());
        packBean.addColumnQuery("isTookEffect", " or model." + "isTookEffect" + " = :m_" + "isTookEffect" + " )", MesPcnExtEnumUtil.TRUE_OR_FALSE.FALSE.getValue());
        List<MesBomPendingPart> bomPendingPartDbListByNotRemind = bomPendingPartRepository.findByHqlWhere(packBean);

        List<String> itemPartNoList = bomPendingPartDbListByNotRemind.stream().map(MesBomPendingPart::getItemPartNo).distinct().collect(Collectors.toList());

        if (!CollectionUtils.isEmpty(itemPartNoList)) oldItemPartNoList.removeAll(itemPartNoList);
    }

    private void removeSamePartByNewBom(List<String> oldItemPartNoList, List<WmsBomTotalModel> wmsBomTotalModels) {

        if (CollectionUtils.isEmpty(wmsBomTotalModels) || CollectionUtils.isEmpty(oldItemPartNoList)) return;

        List<String> newItemPartNoList = wmsBomTotalModels.stream().map(WmsBomTotalModel::getItemPartNo).collect(Collectors.toList());

        oldItemPartNoList.removeAll(newItemPartNoList);
    }

    private BaseResultBean doWmsBomEffect(String organizeCode, String partNo) {
        String bomEffectRequestUrl = pcnHttpService.getRequestUrl(organizeCode, MesPcnExtConstWords.BOM_TASK_EFFECT);
        Map<String, String> params = new HashMap<>();
        params.put(MesPcnExtConstWords.PART_NO, partNo);
        params.put(MesPcnExtConstWords.ORGANIZE_CODE, organizeCode);
        String bomEffectData = PcnHttpUtil.doPost(bomEffectRequestUrl, params);
        log.info("HTTP调用MES微服务接口得到结果:{}", bomEffectData);

        BaseResultBean bomEffectResultBean = null;
        if (!StringUtils.isEmpty(bomEffectData)) {
            bomEffectResultBean = JsonUtilTool.decode(bomEffectData, BaseResultBean.class);
        } else {
            log.error("HTTP[{}]调用mes Bom生效接口失败", bomEffectResultBean);
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_EXIT.getCode())
                    .setErrorDetail("HTTP调用mes Bom生效接口失败,请联系管理员")
                    .build();
        }
        return bomEffectResultBean;
    }

    private void saveNewPartBom(List<WmsBomTotalModel> wmsBomTotalModels, String userName) {
        List<MesBom> mesBomList = new ArrayList<>();

        for (WmsBomTotalModel wmsBomTotalModel : wmsBomTotalModels) {
            MesBom bom = new MesBom();
            BeanUtils.copyProperties(wmsBomTotalModel, bom, "id");
            bom.setUnit(wmsBomTotalModel.getUNIT());
            bom.setBomCode(wmsBomTotalModel.getBomNum());
            ConvertBean.serviceModelInitialize(bom, userName);
            mesBomList.add(bom);
        }

        bomRepository.saveAll(mesBomList);
    }

    private List<MesBom> queryOldPartBom(String organizeCode, String partNo) {
        return bomRepository.findByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.PART_NO},
                new Object[]{organizeCode, CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue(), partNo});
    }

    private List<MesBom> queryBomByItemPartNo(String organizeCode, List<String> itemPartNo) {

        List<MesBom> bomList = new ArrayList<>();

        int batchHandleNum = 100;

        for (int i = 0; i < itemPartNo.size(); i += batchHandleNum) {
            List<String> itemPartNoByPart = itemPartNo.subList(i, Math.min(i + batchHandleNum, itemPartNo.size()));
            DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
            DdlPreparedPack.getInPackList(itemPartNoByPart, MesPcnExtConstWords.ITEM_PART_NO, packBean);
            List<MesBom> bomTempList = bomRepository.findByHqlWhere(packBean);
            bomList.addAll(bomTempList);
        }

        return bomList;
    }

    private void saveBomEffectRecord(String organizeCode, String userName, String partNo, String workOrderNo, String productSn) {
        MesBomTakeEffectRecord bomTakeEffectRecord = new MesBomTakeEffectRecord();
        bomTakeEffectRecord.setWorkOrderNo(workOrderNo);
        bomTakeEffectRecord.setPartNo(partNo);

        MesPartExt partExt = partExtRDao.getByProperty(
                new String[]{MesConstWords.ORGANIZE_CODE, MesConstWords.IS_DELETED, MesConstWords.IS_VALID, MesPcnExtConstWords.PART_NO},
                new Object[]{organizeCode, CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), partNo});
        if (null != partExt) {
            bomTakeEffectRecord.setPartName(partExt.getPartName());
        }
        bomTakeEffectRecord.setTakeEffectTime(TimeTool.getNowTime(true));
        bomTakeEffectRecord.setTaskUser(userName);
        bomTakeEffectRecord.setProductSn(productSn);
        bomTakeEffectRecord.setOrganizeCode(organizeCode);
        ConvertBean.serviceModelInitialize(bomTakeEffectRecord, userName);
        bomTakeEffectRecordRepository.save(bomTakeEffectRecord);
    }

}
