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

import cn.estsh.i3plus.ext.mes.pcn.api.base.IPartExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.base.IShiftExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.base.ISxPcnHttpService;
import cn.estsh.i3plus.ext.mes.pcn.api.base.bu.IBuShiftProdCenterRecordService;
import cn.estsh.i3plus.ext.mes.pcn.api.base.bu.IMesBusiConfigService;
import cn.estsh.i3plus.ext.mes.pcn.api.base.bu3.ISxPartCategoryPlanRateService;
import cn.estsh.i3plus.ext.mes.pcn.pojo.bean.*;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.ShiftProdCenterModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.ShiftProdCenterRecordModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.ShiftProdModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.SxQmsPointSampleLedgerModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.bu.AndonShiftProdCenterRecordModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.repository.*;
import cn.estsh.i3plus.ext.mes.pcn.pojo.sqlpack.MesPcnExtHqlPack;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.ConvertBeanExt;
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.MathOperation;
import cn.estsh.i3plus.platform.common.tool.TimeTool;
import cn.estsh.i3plus.pojo.base.bean.BaseResultBean;
import cn.estsh.i3plus.pojo.base.bean.DdlPackBean;
import cn.estsh.i3plus.pojo.base.bean.ListPager;
import cn.estsh.i3plus.pojo.base.common.Pager;
import cn.estsh.i3plus.pojo.base.common.PagerHelper;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.enumutil.ResourceEnumUtil;
import cn.estsh.i3plus.pojo.base.tool.DdlPreparedPack;
import cn.estsh.i3plus.pojo.mes.bean.MesPart;
import cn.estsh.i3plus.pojo.mes.bean.MesShift;
import cn.estsh.i3plus.pojo.mes.bean.MesWorkOrder;
import cn.estsh.i3plus.pojo.mes.repository.MesWorkOrderRepository;
import cn.estsh.impp.framework.boot.exception.ImppExceptionBuilder;
import cn.estsh.impp.framework.boot.util.ImppRedis;
import cn.estsh.impp.framework.boot.util.ResultBean;
import com.alibaba.fastjson.JSONObject;
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 javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author wangjie
 * @version 1.0
 * @date 2021/1/13 9:28
 **/
@Slf4j
@Service
public class BuShiftProdCenterRecordService implements IBuShiftProdCenterRecordService {

    @Autowired
    private IShiftExtService shiftExtService;

    @Autowired
    private MesWorkCenterExtRepository workCenterExtRepository;

    @Autowired
    private MesShiftProdCenterRecordRepository shiftProdCenterRecordRepository;

    @Autowired
    private MesShiftProdCenterRepository shiftProdCenterRepository;

    @Autowired
    private MesShiftProdRepository shiftProdRepository;

    @Autowired
    private IPartExtService partExtService;

    @Autowired
    private MesOutPutStatisticsRepository outPutStatisticsRepository;

    @Autowired
    private ISxPcnHttpService pcnHttpService;

    @Autowired
    private IMesBusiConfigService busiConfigService;

    @Autowired
    private ISxPartCategoryPlanRateService partCategoryPlanRateService;

    @Resource(name = MesPcnExtConstWords.REDIS_RES_PCN)
    private ImppRedis redisMesPcn;

    @Autowired
    private MesWorkOrderRepository workOrderRepository;

    @Autowired
    private MesWorkCenterNotReachReasonRepository workCenterNotReachReasonRepository;


    @Override
    public List<MesShiftExt> queryShiftAll(MesShiftExt shiftExt) {
        return shiftExtService.queryShiftAll(shiftExt);
    }

    @Override
    public ShiftProdCenterModel queryShiftProdCenterData(MesShiftExt shiftExt) {
        ShiftProdCenterModel shiftProdCenterModel = new ShiftProdCenterModel();
        shiftProdCenterModel.setShiftList(queryShiftAll(shiftExt));
        MesWorkCenterExt workCenter = getWorkCenter(shiftExt.getOrganizeCode(), shiftExt.getAreaCode(), shiftExt.getWorkCenterCode());
        if (null == workCenter) {
            return shiftProdCenterModel;
        }
        shiftProdCenterModel.setWorkCenterCode(workCenter.getWorkCenterCode());
        shiftProdCenterModel.setWorkCenterName(workCenter.getWorkCenterName());
        shiftProdCenterModel.setWorkerQty(workCenter.getWorkerQty());
        shiftProdCenterModel.setWorkTime(workCenter.getWorkTime());
        if (!StringUtils.isEmpty(workCenter.getShiftCode()) && !StringUtils.isEmpty(workCenter.getWorkTime())) {
            shiftProdCenterModel.setShiftCode(workCenter.getShiftCode());
            MesShiftExt shiftExtDb = shiftExtService.getShiftExtByShiftCodeAndCenterCode(shiftExt.getOrganizeCode(), workCenter.getWorkCenterCode(), workCenter.getShiftCode());
            if (null != shiftExtDb) {
                shiftProdCenterModel.setShiftName(shiftExtDb.getShiftName());
                shiftProdCenterModel.setShiftStartTime(shiftExtDb.getStartTime());
                shiftProdCenterModel.setShiftEndTime(shiftExtDb.getEndTime());

                //当前时间(YYYY-MM-dd)
                String currentTimeYmd = workCenter.getWorkTime();
                //判断当前班次时间是否跨天,结束时间小于等于开始时间即跨天,否则当天
                Boolean isNextDayFlagShift = compareHms(shiftExtDb.getStartTime(), shiftExtDb.getEndTime());
                //班次实际开始时间(YYYY-MM-dd HH:mm:ss) [当前年月日 + 班次开始时间]
                String shiftStartYmdHms = currentTimeYmd + MesPcnExtConstWords.ONE_SPACE + shiftExtDb.getStartTime();
                //班次实际结束时间(YYYY-MM-dd HH:mm:ss) [if 当天: 当前年月日 + 班次结束时间][else : 明天年月 + 班次结束时间]
                String shiftEndYmdHms = getEndDateByFlag(isNextDayFlagShift, currentTimeYmd, shiftExtDb.getEndTime());

                shiftProdCenterModel.setShiftStartTimeYmdHms(shiftStartYmdHms);
                shiftProdCenterModel.setShiftEndTimeYmdHms(shiftEndYmdHms);
            }
            List<MesShiftProdCenterRecord> shiftProdCenterRecordList = getShiftProdCenterRecordList(
                    shiftExt.getOrganizeCode(), workCenter.getWorkTime(), workCenter.getWorkCenterCode(), workCenter.getShiftCode(),MesPcnExtEnumUtil.SHIFT_PROD_TYPE.NORMAL_STOP_CENTER.getValue());
            if (!CollectionUtils.isEmpty(shiftProdCenterRecordList)) {
                shiftProdCenterModel.setShiftProdCenterRecordList(packShiftProdCenterRecordList(shiftProdCenterRecordList, shiftExtDb));
            }
        }
        return shiftProdCenterModel;
    }

    private List<ShiftProdCenterRecordModel> packShiftProdCenterRecordList(List<MesShiftProdCenterRecord> shiftProdCenterRecordList, MesShiftExt shift) {
        Map<String, String> careerMap = busiConfigService.getConfigMap(shift.getOrganizeCode(), MesPcnExtConstWords.SX_CAREER_CFG);
        Map<String, String> categoryMap = partCategoryPlanRateService.getCategoryMap(shift.getOrganizeCode());

        List<ShiftProdCenterRecordModel> modelList = new ArrayList<>();
        for (MesShiftProdCenterRecord shiftProdCenterRecord : shiftProdCenterRecordList) {
            if (null == shiftProdCenterRecord) {
                continue;
            }
            ShiftProdCenterRecordModel model = new ShiftProdCenterRecordModel();
            BeanUtils.copyProperties(shiftProdCenterRecord, model);
            model.setProdCategoryName(StringUtils.isEmpty(shiftProdCenterRecord.getProdCategory()) ?
                    null : MesPcnExtEnumUtil.SHIFT_PROD_CATEGORY.valueOfDescription(shiftProdCenterRecord.getProdCategory()));
            model.setProdTypeName(StringUtils.isEmpty(shiftProdCenterRecord.getProdType()) ?
                    null : MesPcnExtEnumUtil.SHIFT_PROD_TYPE.valueOfDescription(shiftProdCenterRecord.getProdType()));
            model.setIsProdTimeName(StringUtils.isEmpty(shiftProdCenterRecord.getIsProdTime()) ?
                    null : MesPcnExtEnumUtil.SHIFT_PROD_IS_PROD_TIME.valueOfDescription(shiftProdCenterRecord.getIsProdTime()));
            model.setCareerName((!StringUtils.isEmpty(model.getCareerCode()) && !CollectionUtils.isEmpty(careerMap) &&
                    careerMap.containsKey(model.getCareerCode())) ? careerMap.get(model.getCareerCode()) : null);
            model.setCategoryName((!StringUtils.isEmpty(model.getCategoryCode()) && !CollectionUtils.isEmpty(categoryMap) &&
                    categoryMap.containsKey(model.getCategoryCode())) ? categoryMap.get(model.getCategoryCode()) : null);
            if (null != shift) {
                model.setShiftStartTime(shift.getStartTime());
                model.setShiftEndTime(shift.getEndTime());
            }
            model.setPartNo(shiftProdCenterRecord.getPartNo());
            modelList.add(model);
        }
        return modelList;
    }

    private List<MesShiftProdCenterRecord> getShiftProdCenterRecordList(String organizeCode, String workTime, String workCenterCode, String shiftCode) {
        return shiftProdCenterRecordRepository.findByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID,
                        MesPcnExtConstWords.WORK_CENTER_CODE, MesPcnExtConstWords.SHIFT_CODE, MesPcnExtConstWords.WORK_TIME},
                new Object[]{organizeCode, CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(),
                        workCenterCode, shiftCode, workTime});
    }


    private List<MesShiftProdCenterRecord> getShiftProdCenterRecordList(String organizeCode, String workTime, String workCenterCode, String shiftCode,Integer prodType) {
        //停机记录中不展示常规停机数据
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(workCenterCode, MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(shiftCode,MesPcnExtConstWords.SHIFT_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(workTime,MesPcnExtConstWords.WORK_TIME, packBean);
        DdlPreparedPack.getNumNOEqualPack(prodType,MesPcnExtConstWords.PROD_TYPE,packBean);
        return shiftProdCenterRecordRepository.findByHqlWhere(packBean);
    }

    public MesWorkCenterExt getWorkCenter(String organizeCode, String workCenterCode) {
        return workCenterExtRepository.getByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.WORK_CENTER_CODE},
                new Object[]{organizeCode, CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), workCenterCode});
    }

    public MesWorkCenterExt getWorkCenter(String organizeCode, String areaCode, String workCenterCode) {
        return workCenterExtRepository.getByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID,
                        MesPcnExtConstWords.AREA_CODE, MesPcnExtConstWords.WORK_CENTER_CODE},
                new Object[]{organizeCode, CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(),
                        areaCode, workCenterCode});
    }

    @Override
    public ResultBean doShiftProdCenterStop(MesWorkCenterExt workCenter, String partNo, String notReachReason) {

        MesWorkCenterExt workCenterDb = getWorkCenter(workCenter.getOrganizeCode(), workCenter.getAreaCode(), workCenter.getWorkCenterCode());
        if (null == workCenterDb) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("区域代码[%s]生产线代码[%s]对应的信息不存在", workCenter.getAreaCode(), workCenter.getWorkCenterCode())
                    .build();
        }
        if (StringUtils.isEmpty(workCenterDb.getShiftCode()) || StringUtils.isEmpty(workCenterDb.getWorkTime())) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("生产线[%s]未启动班次,不能执行结束班次操作", workCenter.getWorkCenterCode())
                    .build();
        }

        //当前停机记录表的常规生产和非常规生产的数据条目小于同班次产线时间的产量统计表中的条目数不能结束班次
        checkMesOutPutStaRecord(workCenter);

        List<BigDecimal> reachRateAndCompleteRate = getReachRateAndCompleteRate(workCenter);

        //String key = new StringJoiner(MesPcnExtConstWords.COLON).add(workCenter.getOrganizeCode()).add(workCenter.getWorkCenterCode()).toString();

        if ((reachRateAndCompleteRate.get(0).compareTo(new BigDecimal("100.0")) < 0 || reachRateAndCompleteRate.get(1).compareTo(new BigDecimal("100.0")) < 0) && (StringUtils.isEmpty(partNo) || StringUtils.isEmpty(notReachReason))) {
            //redisMesPcn.putObject(key,TimeTool.getNowTime(true),15*60L);
            return ResultBean.success(String.format("产线【%s】 达成率【%s】 完结率【%s】低于%s，请录入未达成原因", workCenter.getWorkCenterCode(), reachRateAndCompleteRate.get(0).doubleValue() + "%" , reachRateAndCompleteRate.get(1).doubleValue() + "%", "100%")).setCode("200011");
        } else {
            workCenterDb.setShiftCode(null);
            workCenterDb.setWorkTime(null);
            workCenterDb.setWorkerQty(null);
            ConvertBean.serviceModelUpdate(workCenterDb, workCenter.getModifyUser());
            new ConvertBeanExt(workCenterDb).convertBean(workCenterDb);
            workCenterExtRepository.save(workCenterDb);

            MesWorkCenterNotReachReason workCenterNotReachReason = workCenterNotReachReasonRepository.getByProperty(
                    new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.WORK_CENTER_CODE, MesPcnExtConstWords.WORK_TIME},
                    new Object[]{workCenter.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.VALID, workCenter.getWorkCenterCode(), workCenter.getWorkTime()});

            if (workCenterNotReachReason == null) {
                workCenterNotReachReason = new MesWorkCenterNotReachReason();
                ConvertBean.serviceModelInitialize(workCenterNotReachReason, workCenter.getModifyUser());
                workCenterNotReachReason.setWorkCenterCode(workCenter.getWorkCenterCode());
                workCenterNotReachReason.setWorkTime(workCenter.getWorkTime());
            }
            workCenterNotReachReason.setYieldRate(reachRateAndCompleteRate.get(0).doubleValue());
            workCenterNotReachReason.setCompleteRate(reachRateAndCompleteRate.get(1).doubleValue());
            workCenterNotReachReason.setPlanQty(reachRateAndCompleteRate.get(2).doubleValue());
            workCenterNotReachReason.setCompleteQty(reachRateAndCompleteRate.get(3).doubleValue());
            workCenterNotReachReason.setPartNo(partNo);
            workCenterNotReachReason.setNotReachReason(notReachReason);
            workCenterNotReachReason.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            workCenterNotReachReasonRepository.save(workCenterNotReachReason);
        }

        return ResultBean.success("结束成功").setCode(ResourceEnumUtil.MESSAGE.SUCCESS.getCode());
    }

    private List<BigDecimal> getReachRateAndCompleteRate(MesWorkCenterExt workCenter) {
        List<MesWorkOrder> workOrderList = getMesWorkOrderList(workCenter.getOrganizeCode(), workCenter.getWorkTime(), workCenter.getWorkCenterCode());

        List<String> workOrderNoList = new ArrayList<>();

        List<MesOutPutStatistics> outPutStatisticsByWorkCenterCode = getOutPutStatisticsList(workCenter.getWorkCenterCode(), workCenter.getWorkTime(), workCenter.getOrganizeCode());

        Map<String, MesWorkOrder> workOrderMapByOrderNo = workOrderList.stream().collect(Collectors.toMap(MesWorkOrder::getOrderNo, Function.identity(), (x, y) -> y));

        Map<String, List<MesOutPutStatistics>> outPutStatisticsMapByOrderNo = outPutStatisticsByWorkCenterCode.stream().collect(Collectors.groupingBy(MesOutPutStatistics::getWorkOrderNo));

        if (!CollectionUtils.isEmpty(workOrderMapByOrderNo)) workOrderNoList.addAll(workOrderMapByOrderNo.keySet());

        if (!CollectionUtils.isEmpty(outPutStatisticsMapByOrderNo)) workOrderNoList.addAll(outPutStatisticsMapByOrderNo.keySet());

        workOrderNoList = workOrderNoList.stream().distinct().collect(Collectors.toList());

        Map<String, Double> planQtyMapByPartNo = new HashMap<>();
        Map<String, Double> completeQtyMapByPartNo = new HashMap<>();

        for (String workOrderNo : workOrderNoList) {

            if (outPutStatisticsMapByOrderNo.containsKey(workOrderNo)) {

                List<MesOutPutStatistics> outPutStatisticsByWorkOrderNo = outPutStatisticsMapByOrderNo.get(workOrderNo);

                String partNo = outPutStatisticsByWorkOrderNo.get(0).getPartNo();

                List<MesOutPutStatistics> useOutPutStatisticsQtyList = outPutStatisticsByWorkOrderNo.stream().filter(o -> CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValueStr().equals(o.getOutPutFlag())).collect(Collectors.toList());

                if (CollectionUtils.isEmpty(useOutPutStatisticsQtyList) && workOrderMapByOrderNo.containsKey(workOrderNo)) {

                    MesWorkOrder workOrder = workOrderMapByOrderNo.get(workOrderNo);

                    planQtyMapByPartNo.put(workOrder.getPartNo(), MathOperation.add(planQtyMapByPartNo.getOrDefault(workOrder.getPartNo(), 0.0), workOrder.getQty()));

                } else if(!CollectionUtils.isEmpty(useOutPutStatisticsQtyList)) {

                    planQtyMapByPartNo.put(partNo, MathOperation.add(planQtyMapByPartNo.getOrDefault(partNo, 0.0), useOutPutStatisticsQtyList.stream().mapToDouble(MesOutPutStatistics::getQty).sum()));

                } else {

                    planQtyMapByPartNo.put(partNo, MathOperation.add(planQtyMapByPartNo.getOrDefault(partNo, 0.0), 0));

                }

                completeQtyMapByPartNo.put(partNo, MathOperation.add(completeQtyMapByPartNo.getOrDefault(partNo, 0.0),
                        MathOperation.sub(outPutStatisticsByWorkOrderNo.stream().mapToDouble(MesOutPutStatistics::getQty).sum(),
                                outPutStatisticsByWorkOrderNo.stream().mapToDouble(MesOutPutStatistics::getRemakeQty).sum())));

            } else {
                MesWorkOrder workOrder = workOrderMapByOrderNo.get(workOrderNo);
                planQtyMapByPartNo.put(workOrder.getPartNo(), MathOperation.add(planQtyMapByPartNo.getOrDefault(workOrder.getPartNo(), 0.0), workOrder.getQty()));
                if (!completeQtyMapByPartNo.containsKey(workOrder.getPartNo())) completeQtyMapByPartNo.put(workOrder.getPartNo(), 0.0);
            }
        }

        /* 完结率=完成个数➗总个数
           产量➗计划数>=95% 算完成，按物料编码分组。*/
        int completeCount = 0;
        for (Map.Entry<String, Double> completeQtyEntry : completeQtyMapByPartNo.entrySet()) {
            if (Double.compare(MathOperation.div(completeQtyEntry.getValue(), planQtyMapByPartNo.get(completeQtyEntry.getKey())), 0.95) >= 0) completeCount++;
        }

        // 完结率
        BigDecimal completeRate = divThenMul100Format2RoundHalfUp((double)completeCount, (double)completeQtyMapByPartNo.keySet().size());

        // 总计划数量
        double totalPlanQty = planQtyMapByPartNo.values().stream().mapToDouble(Double::doubleValue).sum();
        // 总完成数量
        double totalCompleteQty = completeQtyMapByPartNo.values().stream().mapToDouble(Double::doubleValue).sum();

        // 达成率
        BigDecimal yieldRate = divThenMul100Format2RoundHalfUp(totalCompleteQty, totalPlanQty);
        List<BigDecimal> rateList =  new ArrayList<>();
        rateList.add(yieldRate);
        rateList.add(completeRate);
        rateList.add(new BigDecimal(totalPlanQty + ""));
        rateList.add(new BigDecimal(totalCompleteQty + ""));
        return rateList;
    }

    public static BigDecimal divThenMul100Format2RoundHalfUp(Double d1, Double d2) {
        return format2RounHalfUp(MathOperation.mul(MathOperation.div(d1, d2), 100));
    }

    private static BigDecimal format2RounHalfUp(Double d) {
        if (StringUtils.isEmpty(d)) d = new Double(0);
        BigDecimal bd = new BigDecimal(d);
        bd = bd.setScale(2, BigDecimal.ROUND_HALF_UP);
        return bd;
    }

    private List<MesOutPutStatistics> getOutPutStatisticsList(String workCenterCode, String workTime, String organizeCode) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(workCenterCode, MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(workTime, MesPcnExtConstWords.WORK_TIME, packBean);
        return outPutStatisticsRepository.findByHqlWhere(packBean);
    }

    private List<MesWorkOrder> getMesWorkOrderList(String organizeCode, String workTime, String workCenterCode) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.timeBuilder(workTime + MesPcnExtConstWords.APPEND_ZERO_HMS, workTime + MesPcnExtConstWords.APPEND_24_HMS, MesPcnExtConstWords.START_TIME, packBean, true);
        DdlPreparedPack.getNumEqualPack(MesPcnExtEnumUtil.WORK_ORDER_TYPE.STANDARD_ORDER.getValue(), MesPcnExtConstWords.WORK_ORDER_TYPE, packBean);
        DdlPreparedPack.getStringEqualPack(workCenterCode, MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
        List<MesWorkOrder> workOrderDbList = workOrderRepository.findByHqlWhere(packBean);
        if (!CollectionUtils.isEmpty(workOrderDbList)) workOrderDbList = workOrderDbList.stream().filter(o -> o.getWorkOrderStatus() != MesPcnExtEnumUtil.WORK_ORDER_STATUS.REMOVE.getValue() || o.getWorkOrderStatus() != MesPcnExtEnumUtil.WORK_ORDER_STATUS.CREATE.getValue() || o.getWorkOrderType() != MesPcnExtEnumUtil.WORK_ORDER_TYPE.REWORK_ORDER.getValue() ).collect(Collectors.toList());
        return workOrderDbList;
    }


    private void checkMesOutPutStaRecord(MesWorkCenterExt workCenter){
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(workCenter.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(workCenter.getWorkCenterCode(), MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(workCenter.getShiftCode(), MesPcnExtConstWords.SHIFT_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(workCenter.getWorkTime(), MesPcnExtConstWords.WORK_TIME, packBean);
        List<MesOutPutStatistics> mesOutPutStatisticsList = outPutStatisticsRepository.findByHqlWhere(packBean);
        List<Integer> prodTypeList = Stream.of(
                MesPcnExtEnumUtil.SHIFT_PROD_TYPE.NORMAL_PROD.getValue(),
                MesPcnExtEnumUtil.SHIFT_PROD_TYPE.UNNORMAL_PROD.getValue()).collect(Collectors.toList());
        DdlPreparedPack.getInPackList(prodTypeList, MesPcnExtConstWords.PROD_TYPE, packBean);
        List<MesShiftProdCenterRecord> shiftProdCenterRecordList = shiftProdCenterRecordRepository.findByHqlWhere(packBean);
        //分别获取停开机时间记录表和产量统计表的数据 当当前停机记录表的常规生产和非常规生产的数据条目小于同班次产线时间的产量统计表中的条目数不能结束班次
        if((CollectionUtils.isEmpty(shiftProdCenterRecordList) && !CollectionUtils.isEmpty(mesOutPutStatisticsList))  ||
                (!CollectionUtils.isEmpty(shiftProdCenterRecordList) && !CollectionUtils.isEmpty(mesOutPutStatisticsList) &&
                        shiftProdCenterRecordList.size() < mesOutPutStatisticsList.size())){
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("生产线[%s]生产工单数量与生产时间条数不符，无法结束班次", workCenter.getWorkCenterCode())
                    .build();

        }
    }

    @Override
    public void doShiftProdCenterStart(MesWorkCenterExt workCenter) {
        MesShift shiftDb = shiftExtService.getShiftByShiftCodeAndCenterCode(workCenter.getOrganizeCode(), workCenter.getWorkCenterCode(), workCenter.getShiftCode());
        if (null == shiftDb) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("生产线代码[%s]班次代码[%s]对应的信息不存在", workCenter.getWorkCenterCode(), workCenter.getShiftCode())
                    .build();
        }
        MesWorkCenterExt workCenterDb = getWorkCenter(workCenter.getOrganizeCode(), workCenter.getAreaCode(), workCenter.getWorkCenterCode());
        if (null == workCenterDb) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("区域代码[%s]生产线代码[%s]对应的信息不存在", workCenter.getAreaCode(), workCenter.getWorkCenterCode())
                    .build();
        }
        Map<String, String> params = new HashMap<>();
        params.put(MesPcnExtConstWords.PRO_LINE_CODE, workCenter.getWorkCenterCode());
        params.put(MesPcnExtConstWords.ORGANIZE_CODE, workCenter.getOrganizeCode());
        String requestUrl = pcnHttpService.getRequestUrl(workCenter.getOrganizeCode(), MesPcnExtConstWords.FIND_BY_PRO_LINE_CODE);
        String data = null;
        try {
            data = PcnHttpUtil.doGet(requestUrl, params);
        } catch (UnsupportedEncodingException e) {
            log.error("HTTP[{}]调用qms获取制造点检样本台账信息信息接口失败", requestUrl);
        }
        BaseResultBean baseResultBean = null;
        List<SxQmsPointSampleLedgerModel> sxQmsPointSampleLedgerModelList = null;
        if (!StringUtils.isEmpty(data)) {
            baseResultBean = JsonUtilTool.decode(data, BaseResultBean.class);
        } else {
            log.error("HTTP[{}]调用qms获取制造点检样本台账信息信息接口失败", requestUrl);
        }
        if (null != baseResultBean && baseResultBean.success
                && null != baseResultBean.getResultList() && baseResultBean.getResultList().size() > 0) {
            List<LinkedHashMap> resultObject = (List<LinkedHashMap>) baseResultBean.getResultList();
            sxQmsPointSampleLedgerModelList = JsonUtilTool.toList(JSONObject.toJSONString(resultObject), SxQmsPointSampleLedgerModel.class);
            SxQmsPointSampleLedgerModel sxQmsPointSampleLedgerModel = sxQmsPointSampleLedgerModelList.iterator().next();
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("当前产线[%s]在【制造点检样本台账】中对应的数据管理编号:[%s] 已超过失效日期,不允许启动班次！",
                            workCenter.getWorkCenterCode(),sxQmsPointSampleLedgerModel.getMangagementCoding())
                    .build();
        }
        //计算作业时间(年月日)
        String workTime = getWorkTime(shiftDb.getStartTime(), shiftDb.getEndTime());

        workCenterDb.setShiftCode(shiftDb.getShiftCode());
        workCenterDb.setWorkerQty(workCenter.getWorkerQty());
        workCenterDb.setWorkTime(workTime);
        ConvertBean.serviceModelUpdate(workCenterDb, workCenter.getModifyUser());
        new ConvertBeanExt(workCenterDb).convertBean(workCenterDb);
        workCenterExtRepository.save(workCenterDb);

        log.info("工位停开机:生产线{}作业时间{}{}已启动,产品别:{}", workCenter.getWorkCenterCode(), workTime, workCenterDb.getShiftCode(), workCenterDb.getCategoryCode());

        //查询停开机记录表,不存在此维度[作业时间+生产线+班次]数据时,查询产线班次固定作业内容信息,存在则遍历插入停开机记录表,需要冗余班次作业项目信息中的字段
        List<MesShiftProdCenterRecord> shiftProdCenterRecordList = getShiftProdCenterRecordList(
                workCenter.getOrganizeCode(), workTime, workCenter.getWorkCenterCode(), shiftDb.getShiftCode());
        if (CollectionUtils.isEmpty(shiftProdCenterRecordList)) {
            List<MesShiftProdCenter> shiftProdCenterList = getShiftProdCenterList(workCenter.getOrganizeCode(), workCenter.getWorkCenterCode(), shiftDb.getShiftCode());
            if (!CollectionUtils.isEmpty(shiftProdCenterList)) {
                //获取班次作业项目表根据作业内容代码分组的数据
                Map<String, List<MesShiftProd>> prodCodeMap = getProdCodeMap(workCenter.getOrganizeCode(), shiftProdCenterList);
                for (MesShiftProdCenter shiftProdCenter : shiftProdCenterList) {
                    if (null == shiftProdCenter) {
                        continue;
                    }
                    MesShiftProdCenterRecord record = new MesShiftProdCenterRecord();
                    record.setWorkCenterCode(workCenter.getWorkCenterCode());
                    record.setShiftCode(shiftDb.getShiftCode());
                    record.setShiftName(shiftDb.getShiftName());
                    record.setProdCode(shiftProdCenter.getProdCode());
                    List<MesShiftProd> shiftProdList = CollectionUtils.isEmpty(prodCodeMap) ? null : prodCodeMap.get(shiftProdCenter.getProdCode());
                    MesShiftProd shiftProd = CollectionUtils.isEmpty(shiftProdList) ? null : shiftProdList.get(0);
                    if (null != shiftProd) {
                        record.setProdName(shiftProd.getProdName());
                        record.setProdType(shiftProd.getProdType());
                        record.setProdCategory(shiftProd.getProdCategory());
                        record.setIsProdTime(shiftProd.getIsProdTime());
                    }
                    record.setWorkTime(workTime);
                    if (TimeTool.stringParseToDate(shiftProdCenter.getStartTime()).compareTo(TimeTool.stringParseToDate(shiftDb.getStartTime())) < 0) {
                        record.setStartTime(calcDay(workTime, 1) + MesPcnExtConstWords.ONE_SPACE + shiftProdCenter.getStartTime());
                    } else {
                        record.setStartTime(workTime + MesPcnExtConstWords.ONE_SPACE + shiftProdCenter.getStartTime());
                    }
                    if (TimeTool.stringParseToDate(shiftProdCenter.getEndTime()).compareTo(TimeTool.stringParseToDate(shiftDb.getStartTime())) <= 0) {
                        record.setEndTime(calcDay(workTime, 1) + MesPcnExtConstWords.ONE_SPACE + shiftProdCenter.getEndTime());
                    } else {
                        record.setEndTime(workTime + MesPcnExtConstWords.ONE_SPACE + shiftProdCenter.getEndTime());
                    }
                    record.setWorkerQty(workCenter.getWorkerQty());
                    record.setCategoryCode(workCenterDb.getCategoryCode());
                    record.setCareerCode(workCenterDb.getCareerCode());
                    record.setOrganizeCode(workCenter.getOrganizeCode());
                    ConvertBean.serviceModelInitialize(record, workCenter.getModifyUser());
                    shiftProdCenterRecordRepository.insert(record);
                }
            }
        }
    }

    private List<MesShiftProdCenter> getShiftProdCenterList(String organizeCode, String workCenterCode, String shiftCode) {
        return shiftProdCenterRepository.findByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID,
                        MesPcnExtConstWords.WORK_CENTER_CODE, MesPcnExtConstWords.SHIFT_CODE},
                new Object[]{organizeCode, CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(),
                        workCenterCode, shiftCode});
    }

    private Map<String, List<MesShiftProd>> getProdCodeMap(String organizeCode, List<MesShiftProdCenter> shiftProdCenterList) {
        List<String> prodCodeList = (shiftProdCenterList.stream().filter(o -> null != o)
                .map(MesShiftProdCenter::getProdCode).collect(Collectors.toList())).stream().distinct().collect(Collectors.toList());
        List<MesShiftProd> shiftProdList = CollectionUtils.isEmpty(prodCodeList) ? null : getShiftProdListByprodCodeList(organizeCode, prodCodeList);
        return CollectionUtils.isEmpty(shiftProdList) ? null : 
                shiftProdList.stream().filter(o -> null != o).collect(Collectors.groupingBy(MesShiftProd::getProdCode));
    }

    private List<MesShiftProd> getShiftProdListByprodCodeList(String organizeCode, List<String> prodCodeList) {
        DdlPackBean ddlPackBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getInPackList(prodCodeList, MesPcnExtConstWords.PROD_CODE, ddlPackBean);
        return shiftProdRepository.findByHqlWhere(ddlPackBean);
    }

    @Override
    public String getWorkTime(String startTime, String endTime) {
        //当前时间(YYYY-MM-dd)
        String currentTimeYmd = TimeTool.getToday();
        //判断当前班次时间是否跨天,结束时间小于等于开始时间即跨天,否则当天
        Boolean isNextDayFlagShift = compareHms(startTime, endTime);
        return !isNextDayFlagShift ?
                currentTimeYmd : //当天:作业时间即为当前年月日
                getWorkTimeForNextDayShift(startTime, endTime, currentTimeYmd); //跨天
    }

    private String getWorkTimeForNextDayShift(String startTime, String endTime, String currentTimeYmd) {
        //跨天
        String currentTimeHms = TimeTool.getNowTime(MesPcnExtConstWords.TIME_FORMAT);
        if (TimeTool.stringParseToDate(currentTimeHms).compareTo(TimeTool.stringParseToDate(startTime)) < 0 &&
                TimeTool.stringParseToDate(currentTimeHms).compareTo(TimeTool.stringParseToDate(endTime)) > 0) {
            //当前时间时分秒小于班次开始时间并且大于班次结束时间时,即班次时间范围外,作业时间即为当前年月日
            return currentTimeYmd;
        } else {
            //当前时间时分秒大于等于班次开始时间或者小于等于班次结束时间时,即班次时间范围内
            if (TimeTool.stringParseToDate(currentTimeHms).compareTo(TimeTool.stringParseToDate(startTime)) >= 0) {
                //当前时间时分秒如果大于等于班次开始时间,作业时间即为当前年月日
                return currentTimeYmd;
            } else {
                //当前时间时分秒如果小于等于班次结束时间,作业时间即为昨天年月日
                return calcDay(currentTimeYmd, -1);
            }
        }
    }

    private Boolean compareHms(String startDate, String endDate) {
        Boolean flag;
        DateFormat sdf = new SimpleDateFormat(MesPcnExtConstWords.TIME_FORMAT);
        try {
            if (sdf.parse(startDate).compareTo(sdf.parse(endDate)) >= 0) {
                flag = true;
            } else {
                flag = false;
            }
        } catch (Exception e) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("时间比较出错")
                    .build();
        }
        return flag;
    }

    private String calcDay(String day, int amount) {
        try {
            DateFormat sdf = new SimpleDateFormat(MesPcnExtConstWords.DATE_FORMAT);
            return TimeTool.timeCalc(sdf.parse(day), Calendar.DATE, amount, MesPcnExtConstWords.DATE_FORMAT);
        } catch (ParseException e) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("时间计算失败")
                    .build();
        }
    }

    @Override
    public ListPager<ShiftProdModel> queryShiftProdByPager(MesShiftProd shiftProd, Pager pager) {
        DdlPackBean hqlPack = MesPcnExtHqlPack.getShiftProd(shiftProd);
        pager = PagerHelper.getPager(pager, shiftProdRepository.findByHqlWhereCount(hqlPack));
        hqlPack.setOrderByStr(shiftProd.orderBy());
        List<MesShiftProd> shiftProdList = shiftProdRepository.findByHqlWherePage(hqlPack, pager);
        List<ShiftProdModel> modelList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(shiftProdList)) {
            for (MesShiftProd prod : shiftProdList) {
                ShiftProdModel model = new ShiftProdModel();
                BeanUtils.copyProperties(prod, model);
                if (null == prod) {
                    continue;
                }
                model.setProdCategoryName(StringUtils.isEmpty(prod.getProdCategory()) ?
                        null : MesPcnExtEnumUtil.SHIFT_PROD_CATEGORY.valueOfDescription(prod.getProdCategory()));
                model.setProdTypeName(StringUtils.isEmpty(prod.getProdType()) ?
                        null : MesPcnExtEnumUtil.SHIFT_PROD_TYPE.valueOfDescription(prod.getProdType()));
                model.setIsProdTimeName(StringUtils.isEmpty(prod.getIsProdTime()) ?
                        null : MesPcnExtEnumUtil.SHIFT_PROD_IS_PROD_TIME.valueOfDescription(prod.getIsProdTime()));
                modelList.add(model);
            }
        }
        return new ListPager(modelList, pager);
    }

    @Override
    public MesShiftProdCenterRecord insertShiftProdCenterRecord(MesShiftProdCenterRecord record) {
        //校验[开始时间是否小于结束时间]
        checkTimeIsValid(record);
        //判断常规生产开始时间和结束时间是否重叠
        if(MesPcnExtEnumUtil.SHIFT_PROD_TYPE.NORMAL_PROD.getValue()==record.getProdType()) {
            checkTimeIsNormprod(record);
        }

        //获取当前选择的班次信息
       /* MesShiftExt shiftExt = getShiftByCenterAndShiftCode(record);

        //校验[开始时间+结束时间] 在班次时间范围内
        checkTimeIsInShiftTime(record, shiftExt);

        //[作业时间+生产线代码+班次代码+作业类型(停机跟生产两个类型)] 校验 [开始时间+结束时间] 重叠
        checkTimeIsOverlap(record);*/

        //更改停开机记录产品别字段
        //updateRecordCategory(record);

        packPartNameRdd(record);

        MesWorkCenterExt workCenterDb = getWorkCenter(record.getOrganizeCode(), record.getWorkCenterCode());
        record.setCategoryCode(workCenterDb.getCategoryCode());
        record.setCareerCode(workCenterDb.getCareerCode());

        ConvertBean.serviceModelInitialize(record, record.getModifyUser());
        //新增与编辑常规生产后，更新常规停机时间在该时间内数据的物料信息
        doUpdateNormalStopCenterPart(record);
        return shiftProdCenterRecordRepository.insert(record);
    }

    //private void updateRecordCategory(MesShiftProdCenterRecord record) {
    //    DdlPackBean packBean = DdlPackBean.getDdlPackBean(record.getOrganizeCode());
    //    DdlPreparedPack.getStringEqualPack(record.getWorkCenterCode(), MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
    //    MesWorkCenterExt workCenterExt = workCenterExtRepository.getByProperty(packBean);
    //    if(workCenterExt != null){
    //        record.setCategoryCode(workCenterExt.getCategoryCode());
    //    }else{
    //        log.error("updateRecordCategory --- 产线{}不存在", record.getWorkCenterCode());
    //    }
    //}

    private void packPartNameRdd(MesShiftProdCenterRecord record) {
        if (!StringUtils.isEmpty(record.getPartNo())) {
            record.setPartNameRdd(getPartNameRdd(record.getOrganizeCode(), record.getPartNo()));
        }
    }

    private String getPartNameRdd(String organizeCode, String partNo) {
        MesPart partDb = partExtService.getPart(organizeCode, partNo);
        return null == partDb ? null : partDb.getPartName();
    }

    private void checkTimeIsValid(MesShiftProdCenterRecord record) {
        if (TimeTool.stringParseToDate(record.getStartTime()).compareTo(TimeTool.stringParseToDate(record.getEndTime())) >= 0) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("选择的时间[%s - %s]无效", record.getStartTime(), record.getEndTime())
                    .build();
        }
    }

    private void checkTimeIsOverlap(MesShiftProdCenterRecord record) {
        //获取[作业时间+生产线代码+班次代码+作业类型(停机跟生产两个类型)] 维度的数据
        List<MesShiftProdCenterRecord> shiftProdCenterRecordList = getShiftProdCenterRecordList(record);
        //遍历并判断重叠的情况
        for (MesShiftProdCenterRecord shiftProdCenterRecord : shiftProdCenterRecordList) {
            if (null == shiftProdCenterRecord ||
                    (!StringUtils.isEmpty(record.getId()) && record.getId().compareTo(shiftProdCenterRecord.getId()) == 0)) {
                continue;
            }
            //存在三种时间重叠的情况
            //if 当前 实际开始时间 大于等于db数据的 实际开始时间 并小于db数据的 实际结束时间
            //if 当前 实际结束时间 大于db数据的 实际开始时间 并小于等于db数据的 实际结束时间
            //if 当前 实际开始时间 小于等于db数据的 实际开始时间 并 当前 实际结束时间 大于等于db数据的 实际结束时间
            if ((TimeTool.stringParseToDate(record.getStartTime()).compareTo(TimeTool.stringParseToDate(shiftProdCenterRecord.getStartTime())) >= 0 &&
                    TimeTool.stringParseToDate(record.getStartTime()).compareTo(TimeTool.stringParseToDate(shiftProdCenterRecord.getEndTime())) < 0) ||
                    (TimeTool.stringParseToDate(record.getEndTime()).compareTo(TimeTool.stringParseToDate(shiftProdCenterRecord.getStartTime())) > 0 &&
                            TimeTool.stringParseToDate(record.getEndTime()).compareTo(TimeTool.stringParseToDate(shiftProdCenterRecord.getEndTime())) <= 0) ||
                    (TimeTool.stringParseToDate(record.getStartTime()).compareTo(TimeTool.stringParseToDate(shiftProdCenterRecord.getStartTime())) <= 0 &&
                            TimeTool.stringParseToDate(record.getEndTime()).compareTo(TimeTool.stringParseToDate(shiftProdCenterRecord.getEndTime())) >= 0)) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("选择的时间[%s - %s]与已存在的数据存在时间重叠",
                                record.getStartTime(), record.getEndTime())
                        .build();
            }
        }
    }





    private List<MesShiftProdCenterRecord> getShiftProdCenterRecordList(MesShiftProdCenterRecord record) {
        //获取作业类型的大类，停机或生产
        List<Integer> prodTypeList = getProdTypeList(record.getProdType());
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(record.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(record.getWorkCenterCode(), MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(record.getShiftCode(), MesPcnExtConstWords.SHIFT_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(record.getWorkTime(), MesPcnExtConstWords.WORK_TIME, packBean);
        List<MesShiftProdCenterRecord> shiftProdCenterRecordList = shiftProdCenterRecordRepository.findByHqlWhere(packBean);
        if (!CollectionUtils.isEmpty(shiftProdCenterRecordList)) {
            List<String> prodCodeList = (shiftProdCenterRecordList.stream().filter(o -> null != o)
                    .map(MesShiftProdCenterRecord::getProdCode).collect(Collectors.toList())).stream().distinct().collect(Collectors.toList());
            List<MesShiftProd> shiftProdList = CollectionUtils.isEmpty(prodCodeList) ? null : getShiftProdList(record.getOrganizeCode(), prodCodeList, prodTypeList);
            if (!CollectionUtils.isEmpty(shiftProdList)) {
                prodCodeList = (shiftProdList.stream().filter(o -> null != o)
                        .map(MesShiftProd::getProdCode).collect(Collectors.toList())).stream().distinct().collect(Collectors.toList());
            }
            List<String> finalProdCodeList = prodCodeList;
            shiftProdCenterRecordList = shiftProdCenterRecordList.stream()
                    .filter(o -> (null != o && !CollectionUtils.isEmpty(finalProdCodeList) && finalProdCodeList.contains(o.getProdCode()))).collect(Collectors.toList());
        }
        return shiftProdCenterRecordList;
    }



    private void checkTimeIsNormprod(MesShiftProdCenterRecord record) {
        //获取常规生产类型
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(record.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(record.getWorkCenterCode(), MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(record.getShiftCode(), MesPcnExtConstWords.SHIFT_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(record.getWorkTime(), MesPcnExtConstWords.WORK_TIME, packBean);
        DdlPreparedPack.getNumEqualPack(MesPcnExtEnumUtil.SHIFT_PROD_TYPE.NORMAL_PROD.getValue(), MesPcnExtConstWords.PROD_TYPE, packBean);
        List<MesShiftProdCenterRecord> shiftProdCenterRecordList = shiftProdCenterRecordRepository.findByHqlWhere(packBean);
        //遍历并判断重叠的情况
        for (MesShiftProdCenterRecord shiftProdCenterRecord : shiftProdCenterRecordList) {
            if (null == shiftProdCenterRecord ||
                    (!StringUtils.isEmpty(record.getId()) && record.getId().compareTo(shiftProdCenterRecord.getId()) == 0)) {
                continue;
            }
            //存在三种时间重叠的情况
            //if 当前 实际开始时间 大于等于db数据的 实际开始时间 并小于db数据的 实际结束时间
            //if 当前 实际结束时间 大于db数据的 实际开始时间 并小于等于db数据的 实际结束时间
            //if 当前 实际开始时间 小于等于db数据的 实际开始时间 并 当前 实际结束时间 大于等于db数据的 实际结束时间
            if ((TimeTool.stringParseToDate(record.getStartTime()).compareTo(TimeTool.stringParseToDate(shiftProdCenterRecord.getStartTime())) >= 0 &&
                    TimeTool.stringParseToDate(record.getStartTime()).compareTo(TimeTool.stringParseToDate(shiftProdCenterRecord.getEndTime())) < 0) ||
                    (TimeTool.stringParseToDate(record.getEndTime()).compareTo(TimeTool.stringParseToDate(shiftProdCenterRecord.getStartTime())) > 0 &&
                            TimeTool.stringParseToDate(record.getEndTime()).compareTo(TimeTool.stringParseToDate(shiftProdCenterRecord.getEndTime())) <= 0) ||
                    (TimeTool.stringParseToDate(record.getStartTime()).compareTo(TimeTool.stringParseToDate(shiftProdCenterRecord.getStartTime())) <= 0 &&
                            TimeTool.stringParseToDate(record.getEndTime()).compareTo(TimeTool.stringParseToDate(shiftProdCenterRecord.getEndTime())) >= 0)) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("选择的时间[%s - %s]与已存在的数据存在时间重叠",
                                record.getStartTime(), record.getEndTime())
                        .build();
            }
        }
    }


    private List<MesShiftProd> getShiftProdList(String organizeCode, List<String> prodCodeList, List<Integer> prodTypeList) {
        DdlPackBean ddlPackBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getInPackList(prodCodeList, MesPcnExtConstWords.PROD_CODE, ddlPackBean);
        DdlPreparedPack.getInPackList(prodTypeList, MesPcnExtConstWords.PROD_TYPE, ddlPackBean);
        return shiftProdRepository.findByHqlWhere(ddlPackBean);
    }

    private List<Integer> getProdTypeList(Integer prodType) {
        List<Integer> prodTypeList = new ArrayList<>();
        if (MesPcnExtEnumUtil.SHIFT_PROD_TYPE.NORMAL_STOP_CENTER.getValue() == prodType ||
                MesPcnExtEnumUtil.SHIFT_PROD_TYPE.UNNORMAL_STOP_CENTER.getValue() == prodType) {
            prodTypeList.add(MesPcnExtEnumUtil.SHIFT_PROD_TYPE.NORMAL_STOP_CENTER.getValue());
            prodTypeList.add(MesPcnExtEnumUtil.SHIFT_PROD_TYPE.UNNORMAL_STOP_CENTER.getValue());
        } else {
            prodTypeList.add(MesPcnExtEnumUtil.SHIFT_PROD_TYPE.NORMAL_PROD.getValue());
            prodTypeList.add(MesPcnExtEnumUtil.SHIFT_PROD_TYPE.UNNORMAL_PROD.getValue());
        }
        return prodTypeList;
    }

    private void checkTimeIsInShiftTime(MesShiftProdCenterRecord record, MesShiftExt shiftExt) {
        //当前时间(YYYY-MM-dd)
        String currentTimeYmd = record.getWorkTime();
        //判断当前班次时间是否跨天,结束时间小于等于开始时间即跨天,否则当天
        Boolean isNextDayFlagShift = compareHms(shiftExt.getStartTime(), shiftExt.getEndTime());
        //班次实际开始时间(YYYY-MM-dd HH:mm:ss) [当前年月日 + 班次开始时间]
        String shiftStartYmdHms = currentTimeYmd + MesPcnExtConstWords.ONE_SPACE + shiftExt.getStartTime();
        //班次实际结束时间(YYYY-MM-dd HH:mm:ss) [if 当天: 当前年月日 + 班次结束时间][else : 明天年月 + 班次结束时间]
        String shiftEndYmdHms = getEndDateByFlag(isNextDayFlagShift, currentTimeYmd, shiftExt.getEndTime());

        //判断是否在班次时间范围内 [当前 实际开始时间 小于 班次的 实际开始时间 或者 当前 实际结束时间 大于 班次的 实际结束时间]
        if (TimeTool.stringParseToDate(record.getStartTime()).compareTo(TimeTool.stringParseToDate(shiftStartYmdHms)) < 0 ||
                TimeTool.stringParseToDate(record.getEndTime()).compareTo(TimeTool.stringParseToDate(shiftEndYmdHms)) > 0) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("选择的时间[%s - %s]不在班次时间[%s - %s]的范围内",
                            record.getStartTime(), record.getEndTime(), shiftStartYmdHms, shiftEndYmdHms)
                    .build();
        }
    }

    private String getEndDateByFlag(Boolean isNextDayFlag, String currentTimeYmd, String endTime) {
        return !isNextDayFlag ? (currentTimeYmd + MesPcnExtConstWords.ONE_SPACE + endTime) :
                (calcDay(currentTimeYmd, 1) + MesPcnExtConstWords.ONE_SPACE + endTime);
    }

    private MesShiftExt getShiftByCenterAndShiftCode(MesShiftProdCenterRecord record) {
        MesShiftExt shiftExt = shiftExtService.getShiftExtByShiftCodeAndCenterCode(record.getOrganizeCode(), record.getWorkCenterCode(), record.getShiftCode());
        if (null == shiftExt) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                    .setErrorDetail("生产线代码[%s]班次代码[%s]记录不存在", record.getShiftCode(), record.getWorkCenterCode())
                    .build();
        }
        return shiftExt;
    }

    @Override
    public MesShiftProdCenterRecord updateShiftProdCenterRecord(MesShiftProdCenterRecord record) {
        MesShiftProdCenterRecord shiftProdCenterRecordDb = getShiftProdCenterRecordById(record.getId());
        if (CommonEnumUtil.IS_VAILD.INVAILD.getValue() == shiftProdCenterRecordDb.getIsValid()) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                    .setErrorDetail("ID[%s]记录已被禁用,不能修改", record.getId())
                    .build();
        }

        //校验[开始时间是否小于结束时间]
        checkTimeIsValid(record);


        if(MesPcnExtEnumUtil.SHIFT_PROD_TYPE.NORMAL_PROD.getValue()==record.getProdType()) {
            checkTimeIsNormprod(record);
        }

        //获取当前选择的班次信息
//        MesShiftExt shiftExt = getShiftByCenterAndShiftCode(record);
//
//        if (!shiftProdCenterRecordDb.getStartTime().equals(record.getStartTime()) ||
//                !shiftProdCenterRecordDb.getEndTime().equals(record.getEndTime())) {
//            //校验[开始时间+结束时间] 在班次时间范围内
//            checkTimeIsInShiftTime(record, shiftExt);
//
//            //[作业时间+生产线代码+班次代码+作业类型(停机跟生产两个类型)] 校验 [开始时间+结束时间] 重叠
//            checkTimeIsOverlap(record);
//        }

        MesWorkCenterExt workCenterDb = getWorkCenter(record.getOrganizeCode(), record.getWorkCenterCode());
        shiftProdCenterRecordDb.setCategoryCode(workCenterDb.getCategoryCode());
        shiftProdCenterRecordDb.setCareerCode(workCenterDb.getCareerCode());

        shiftProdCenterRecordDb.setStartTime(record.getStartTime());
        shiftProdCenterRecordDb.setEndTime(record.getEndTime());
        shiftProdCenterRecordDb.setWorkerQty(record.getWorkerQty());
        shiftProdCenterRecordDb.setMemo(record.getMemo());
        shiftProdCenterRecordDb.setPartNo(record.getPartNo());
        packPartNameRdd(shiftProdCenterRecordDb);
        ConvertBean.serviceModelUpdate(shiftProdCenterRecordDb, record.getModifyUser());
        //新增与编辑常规生产后，更新常规停机时间在该时间内数据的物料信息
        doUpdateNormalStopCenterPart(shiftProdCenterRecordDb);
        return shiftProdCenterRecordRepository.save(shiftProdCenterRecordDb);
    }

    //新增与编辑常规生产后，更新常规停机时间在该时间内数据的物料信息
    private void doUpdateNormalStopCenterPart(MesShiftProdCenterRecord record){
        if(record.getProdType() == MesPcnExtEnumUtil.SHIFT_PROD_TYPE.NORMAL_PROD.getValue()){
            List<MesShiftProdCenterRecord> mesShiftProdCenterRecords = getMesShiftProdCenterRecords(record);
            mesShiftProdCenterRecords.forEach(o->{
                if(TimeTool.stringParseToDate(o.getStartTime()).compareTo(TimeTool.stringParseToDate(record.getStartTime())) >= 0 &&
                        TimeTool.stringParseToDate(o.getEndTime()).compareTo(TimeTool.stringParseToDate(record.getEndTime())) <= 0){
                    o.setPartNo(record.getPartNo());
                    o.setPartNameRdd(record.getPartNameRdd());
                    ConvertBean.serviceModelUpdate(o, record.getModifyUser());
                }
            });
            shiftProdCenterRecordRepository.saveAll(mesShiftProdCenterRecords);
        }
    }

    private MesShiftProdCenterRecord getShiftProdCenterRecordById(Long id) {
        MesShiftProdCenterRecord shiftProdCenterRecordDb = shiftProdCenterRecordRepository.getById(id);
        if (null == shiftProdCenterRecordDb || CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue() == shiftProdCenterRecordDb.getIsDeleted()) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                    .setErrorDetail("ID[%s]记录不存在", id)
                    .build();
        }
        return shiftProdCenterRecordDb;
    }

    @Override
    public int deleteShiftProdCenterRecodeById(Long id, String modifyUser) {
        return shiftProdCenterRecordRepository.updateByProperties(new String[]{MesPcnExtConstWords.ID}, new Object[]{id},
                new String[]{MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.MODIFY_USER, MesPcnExtConstWords.MODIFY_DATE_TIME},
                new Object[]{CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue(), modifyUser, TimeTool.getNowTime(true)});
    }

    @Override
    public AndonShiftProdCenterRecordModel saveShiftProdCenterRecordFromAndon(Map<String, Object> params) {
        if (CollectionUtils.isEmpty(params)) {
            log.info("ANDON调用PCN记录停开机,入参异常");

            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("ANDON调用PCN记录停开机,入参异常")
                    .build();
        }
        log.info("ANDON调用PCN记录停开机,参数[{}]", JSONObject.toJSONString(params));

        AndonShiftProdCenterRecordModel model = new AndonShiftProdCenterRecordModel();
        MesShiftProdCenterRecord record;
        if (!params.containsKey(MesPcnExtConstWords.ID)) {
            List<Integer> list = new ArrayList<>();
            list.add(MesPcnExtEnumUtil.SHIFT_PROD_TYPE.NORMAL_PROD.getValue());
            list.add(MesPcnExtEnumUtil.SHIFT_PROD_TYPE.UNNORMAL_PROD.getValue());
            DdlPackBean packBean = DdlPackBean.getDdlPackBean((String) params.get(MesPcnExtConstWords.ORGANIZE_CODE));
            DdlPreparedPack.getStringEqualPack((String) params.get(MesPcnExtConstWords.WORK_CENTER_CODE), MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
            DdlPreparedPack.getInPackList(list, MesPcnExtConstWords.PROD_TYPE, packBean);
            DdlPreparedPack.timeBuilder(null, (String) params.get(MesPcnExtConstWords.CALL_TIME), MesPcnExtConstWords.START_TIME, packBean, true);
            DdlPreparedPack.getOrderByPack(new Object[]{CommonEnumUtil.ASC_OR_DESC.DESC.getValue()}, new String[]{MesPcnExtConstWords.START_TIME}, packBean);
            MesShiftProdCenterRecord recordDb = shiftProdCenterRecordRepository.getByProperty(packBean);
            if (null == recordDb) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                        .setErrorDetail("ANDON调用PCN记录停开机,根据生产线代码[%s]未查询到临近呼叫时间[%s]的常规生产或非常规生产类型的停开机记录",
                                params.get(MesPcnExtConstWords.WORK_CENTER_CODE), params.get(MesPcnExtConstWords.CALL_TIME))
                        .build();
            }

            record = new MesShiftProdCenterRecord();
            BeanUtils.copyProperties(recordDb, record, MesPcnExtConstWords.ID);
            record.setProdCode((String) params.get(MesPcnExtConstWords.ALARM_CODE));
            record.setProdName((String) params.get(MesPcnExtConstWords.ALARM_NAME));
            record.setProdCategory(MesPcnExtEnumUtil.SHIFT_PROD_CATEGORY.OTHER.getValue());
            record.setProdType(MesPcnExtEnumUtil.SHIFT_PROD_TYPE.UNNORMAL_STOP_CENTER.getValue());
            record.setStartTime(((String) params.get(MesPcnExtConstWords.CALL_TIME)).substring(0, 16) + MesPcnExtConstWords.APPEND_SECONDS);
            record.setEndTime(TimeTool.timeCalc(
                    TimeTool.stringParseToDate(record.getStartTime(), MesPcnExtConstWords.DATETIME_FORMAT), Calendar.HOUR_OF_DAY, 1, MesPcnExtConstWords.DATETIME_FORMAT));
            record.setAndonOrderNo((String) params.get(MesPcnExtConstWords.ANDON_ORDER_NO));
            record.setMemo((String) params.get(MesPcnExtConstWords.ED_NAME));
            record.setOrganizeCode((String) params.get(MesPcnExtConstWords.ORGANIZE_CODE));
            MesWorkCenterExt workCenterExt = workCenterExtRepository.getByProperty(
                    new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.WORK_CENTER_CODE},
                    new Object[]{record.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), record.getWorkCenterCode()});
            if (null != workCenterExt) {
                record.setCategoryCode(workCenterExt.getCategoryCode());
                record.setCareerCode(workCenterExt.getCareerCode());
            }
            ConvertBean.serviceModelInitialize(record, (String) params.get(MesPcnExtConstWords.CALLER));
            record = shiftProdCenterRecordRepository.insert(record);

            BeanUtils.copyProperties(record, model);
            model.setAndonOrderNo((String) params.get(MesPcnExtConstWords.ANDON_ORDER_NO));
        } else {
            record = shiftProdCenterRecordRepository.getById(Long.parseLong((String) params.get(MesPcnExtConstWords.ID)));
            if (null == record) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                        .setErrorDetail("ANDON调用PCN记录停开机,ID[%s]对应数据不存在", params.get(MesPcnExtConstWords.ID))
                        .build();
            }
            record.setEndTime(((String) params.get(MesPcnExtConstWords.SOLVE_TIME)).substring(0, 16) + MesPcnExtConstWords.APPEND_SECONDS);
            ConvertBean.serviceModelUpdate(record, (String) params.get(MesPcnExtConstWords.SOLVER));
            record = shiftProdCenterRecordRepository.save(record);

            BeanUtils.copyProperties(record, model);
            model.setAndonOrderNo((String) params.get(MesPcnExtConstWords.ANDON_ORDER_NO));
        }
        return model;
    }

    @Override
    public String queryStartTime(MesShiftProdCenterRecord record) {
        String startTime = "";
        if(record.getProdType() == MesPcnExtEnumUtil.SHIFT_PROD_TYPE.NORMAL_PROD.getValue()){
            DdlPackBean packBean = DdlPackBean.getDdlPackBean(record.getOrganizeCode());
            DdlPreparedPack.getStringEqualPack(record.getWorkCenterCode(), MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
            DdlPreparedPack.getStringEqualPack(record.getShiftCode(), MesPcnExtConstWords.SHIFT_CODE, packBean);
            DdlPreparedPack.getStringEqualPack(record.getWorkTime(), MesPcnExtConstWords.WORK_TIME, packBean);
            DdlPreparedPack.getNumEqualPack(MesPcnExtEnumUtil.SHIFT_PROD_TYPE.NORMAL_PROD.getValue(), MesPcnExtConstWords.PROD_TYPE, packBean);
            packBean.setOrderByStr(" order by createDatetime desc ");
            MesShiftProdCenterRecord shiftProdCenterRecord = shiftProdCenterRecordRepository.getByProperty(packBean);

            if(shiftProdCenterRecord == null) {
                MesShiftExt shiftExtDb = shiftExtService.getShiftExtByShiftCodeAndCenterCode(record.getOrganizeCode(), record.getWorkCenterCode(), record.getShiftCode());
                startTime = shiftExtDb != null ? record.getWorkTime() + " " + shiftExtDb.getStartTime() : "";
            }else{
                startTime = shiftProdCenterRecord.getEndTime();
            }
        }
        return startTime;
    }

    private List<MesShiftProdCenterRecord> getMesShiftProdCenterRecords(MesShiftProdCenterRecord record) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(record.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(record.getWorkCenterCode(), MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(record.getShiftCode(), MesPcnExtConstWords.SHIFT_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(record.getWorkTime(), MesPcnExtConstWords.WORK_TIME, packBean);
        return shiftProdCenterRecordRepository.findByHqlWhere(packBean);
    }

}
