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

import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesCustomerSnTransformService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesProduceSnExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesWorkOrderExtService;
import cn.estsh.i3plus.ext.mes.pcn.apiservice.aspect.MonitorLog;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords;
import cn.estsh.i3plus.platform.common.tool.MathOperation;
import cn.estsh.i3plus.platform.common.tool.TimeTool;
import cn.estsh.i3plus.pojo.base.bean.BaseBean;
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.*;
import cn.estsh.i3plus.pojo.mes.repository.MesWorkOrderControlQtyRecordRepository;
import cn.estsh.i3plus.pojo.mes.repository.MesWorkOrderRepository;
import cn.estsh.i3plus.pojo.mes.util.MesExtEnumUtil;
import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class MesWorkOrderExtService implements IMesWorkOrderExtService {

    @Autowired
    private MesWorkOrderRepository workOrderRepository;

    @Autowired
    private IMesProduceSnExtService produceSnExtService;

    @Autowired
    private IMesCustomerSnTransformService customerSnTransformService;

    @Autowired
    private MesWorkOrderControlQtyRecordRepository workOrderControlQtyRecordRepository;

    //根据生产工单号集合 查询生产工单数据
    @Override
    public List<MesWorkOrder> getWorkOrderList(String organizeCode, List<String> workOrderNoList) {

        if (StringUtils.isEmpty(organizeCode) || CollectionUtils.isEmpty(workOrderNoList)) return null;

        workOrderNoList = workOrderNoList.size() == 1 ? workOrderNoList : workOrderNoList.stream().filter(o -> !StringUtils.isEmpty(o)).distinct().collect(Collectors.toList());

        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        if (workOrderNoList.size() == 1) DdlPreparedPack.getStringEqualPack(workOrderNoList.get(0), MesPcnExtConstWords.WORK_ORDER_NO, packBean);
        else DdlPreparedPack.getInPackList(workOrderNoList, MesPcnExtConstWords.WORK_ORDER_NO, packBean);

        return workOrderRepository.findByHqlWhere(packBean);

    }

    //根据生产工单ID查询生产工单信息
    @Override
    public MesWorkOrder getWorkOrder(String organizeCode, Long id) {
        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(id)) return null;
        return workOrderRepository.getByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.ID},
                new Object[]{organizeCode, CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), id});
    }

    @Override
    public MesWorkOrder getWorkOrder(String organizeCode, String workOrderNo) {
        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(workOrderNo)) return null;
        return workOrderRepository.getByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.WORK_ORDER_NO},
                new Object[]{organizeCode, CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), workOrderNo});
    }

    //根据生产工单顺序号,生产线代码查询上一个生产工单信息
    @Override
    public MesWorkOrder getWorkOrder(String organizeCode, String workCenterCode, Long productSeq) {
        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(workCenterCode) || (StringUtils.isEmpty(productSeq) || productSeq.compareTo(0L) == 0)) return null;
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(workCenterCode, MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getNumberSmallerPack(productSeq, MesPcnExtConstWords.PRODUCT_SEQ, packBean);
        DdlPreparedPack.getOrderByPack(new Object[]{CommonEnumUtil.ASC_OR_DESC.DESC.getValue()}, new String[]{MesPcnExtConstWords.PRODUCT_SEQ}, packBean);
        return workOrderRepository.getByProperty(packBean);
    }

    //根据生产工单顺序号,生产线代码查询上一个生产工单信息
    @Override
    public MesWorkOrder getWorkOrderByPart(String organizeCode, String workCenterCode, Long productSeq, String partNo) {
        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(workCenterCode) || (StringUtils.isEmpty(productSeq) || productSeq.compareTo(0L) == 0)) return null;
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(workCenterCode, MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(partNo, MesPcnExtConstWords.PART_NO, packBean);
        DdlPreparedPack.getNumberSmallerPack(productSeq, MesPcnExtConstWords.PRODUCT_SEQ, packBean);
        DdlPreparedPack.getOrderByPack(new Object[]{CommonEnumUtil.ASC_OR_DESC.DESC.getValue()}, new String[]{MesPcnExtConstWords.PRODUCT_SEQ}, packBean);
        return workOrderRepository.getByProperty(packBean);
    }

    //根据生产工单顺序号,生产线代码查询上一个生产工单信息
    @Override
    public MesWorkOrder getWorkOrderByPartAndOrderNo(String organizeCode, String workCenterCode, Long productSeq, String partNo, List<String> workOrderNoList) {
        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(workCenterCode) || (StringUtils.isEmpty(productSeq) || productSeq.compareTo(0L) == 0)) return null;
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(workCenterCode, MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(partNo, MesPcnExtConstWords.PART_NO, packBean);
        DdlPreparedPack.getNumberSmallerPack(productSeq, MesPcnExtConstWords.PRODUCT_SEQ, packBean);
        DdlPreparedPack.getNotInPack(workOrderNoList, MesPcnExtConstWords.WORK_ORDER_NO, packBean);
        DdlPreparedPack.getOrderByPack(new Object[]{CommonEnumUtil.ASC_OR_DESC.DESC.getValue()}, new String[]{MesPcnExtConstWords.PRODUCT_SEQ}, packBean);
        return workOrderRepository.getByProperty(packBean);
    }

    //根据生产工单顺序号,生产线代码,零件生产组代码查询上一个生产工单信息
    @Override
    public MesWorkOrder getWorkOrder(String organizeCode, String workCenterCode, Long productSeq, String partProdGroupCode) {
        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(workCenterCode) || StringUtils.isEmpty(partProdGroupCode) || StringUtils.isEmpty(productSeq) || productSeq.compareTo(0L) == 0) return null;
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(workCenterCode, MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(partProdGroupCode, MesPcnExtConstWords.PART_PROD_GROUP_CODE, packBean);
        DdlPreparedPack.getNumberSmallerPack(productSeq, MesPcnExtConstWords.PRODUCT_SEQ, packBean);
        DdlPreparedPack.getOrderByPack(new Object[]{CommonEnumUtil.ASC_OR_DESC.DESC.getValue()}, new String[]{MesPcnExtConstWords.PRODUCT_SEQ}, packBean);
        return workOrderRepository.getByProperty(packBean);
    }

    //根据生产线代码, 零件生产组代码查询生产工单信息【排序】
    @Override
    public List<MesWorkOrder> getWorkOrderList(String organizeCode, String workCenterCode, String partProdGroupCode) {
        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(workCenterCode) || StringUtils.isEmpty(partProdGroupCode)) return null;
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(workCenterCode, MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(partProdGroupCode, MesPcnExtConstWords.PART_PROD_GROUP_CODE, packBean);
        return workOrderRepository.findByHqlWhere(packBean);
    }

    @Override
    @MonitorLog
    public MesWorkOrder insert(MesWorkOrder item) {
        item.setFid(UUID.randomUUID().toString());
        return workOrderRepository.insert(item);
    }

    @Override
    @MonitorLog
    public void update(MesWorkOrder item) {
        workOrderRepository.update(item);
    }

    @Override
    public void saveAll(List<MesWorkOrder> mesWorkOrderList) {
        workOrderRepository.saveAll(mesWorkOrderList);
    }

    @Override
    public List<MesWorkOrder> getWorkOrderListByShiftCode(String organizeCode, String workCenterCode, String shiftCode) {
        String currentTime = DateUtil.formatDateTime(new Date());
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(workCenterCode, MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(shiftCode, MesPcnExtConstWords.SHIFT_CODE, packBean);
        DdlPreparedPack.getStringSmallerNotEqualPack(currentTime, "planStartTime", packBean);
        DdlPreparedPack.getStringBiggerNotEqualPack(currentTime, "planEndTime", packBean);

        return workOrderRepository.findByHqlWhere(packBean);
    }

    @Override
    public Map<String, Map<String, Object>> getWorkOrderMapSort(String organizeCode, List<String> snList) {
        return getWorkOrderMapSort(organizeCode, snList, null);
    }

    @Override
    public Map<String, Map<String, Object>> getWorkOrderMapSort(String organizeCode, List<String> snList, MesWorkCell workCell) {

        if (StringUtils.isEmpty(organizeCode) || CollectionUtils.isEmpty(snList)) return null;
        snList = snList.size() == 1 ? snList : snList.stream().filter(o -> !StringUtils.isEmpty(o)).distinct().collect(Collectors.toList());

        Map<String, Map<String, Object>> workOrderMap = new HashMap<>();
        for (String sn : snList) {
            if (StringUtils.isEmpty(sn)) continue;
            workOrderMap.put(sn, getWorkOrderMapSort(organizeCode, sn, workCell));
        }

        return workOrderMap;
    }

    @Override
    public Map<String, Object> getWorkOrderMapSort(String organizeCode, String sn) {
        return getWorkOrderMapSort(organizeCode, sn, null);
    }

    @Override
    public Map<String, Object> getWorkOrderMapSort(String organizeCode, String sn, MesWorkCell workCell) {

        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(sn)) return null;

        Map<String, Object> resultMap = new HashMap<>();

        MesProduceSn produceSn;
        if (sn.length() == MesPcnExtConstWords.CUSTOMER_SN_LENGTH_GM) {
            produceSn = produceSnExtService.getProduceSnByCustSn(organizeCode, customerSnTransformService.transformBarCodeGm(sn));
            if (null == produceSn || StringUtils.isEmpty(produceSn.getWorkOrderNo())) resultMap.put(MesPcnExtConstWords.MESSAGE, String.format("请检查工单及客户条码信息,客户条码[%s]信息无效!", sn));
            else resultMap.put(MesProduceSn.class.getSimpleName(), produceSn);
        } else {
            produceSn = produceSnExtService.getProduceSn(organizeCode, sn, sn);
            if (null == produceSn) produceSn = produceSnExtService.getProduceSnByCustSn(organizeCode, sn);
            if (null == produceSn || StringUtils.isEmpty(produceSn.getWorkOrderNo())) resultMap.put(MesPcnExtConstWords.MESSAGE, String.format("请检查工单及产品条码信息,加工单[%s]不存在产品条码信息!", sn));
            else resultMap.put(MesProduceSn.class.getSimpleName(), produceSn);
        }

        if (null != produceSn) {
            MesWorkOrder workOrder = getWorkOrder(organizeCode, produceSn.getWorkOrderNo());
            if (null == workOrder) resultMap.put(MesPcnExtConstWords.MESSAGE, String.format("请检查工单信息,客户条码[%s]对应的加工单[%s]信息不存在!", produceSn.getCustSn(), produceSn.getWorkOrderNo()));
            else resultMap.put(MesWorkOrder.class.getSimpleName(), workOrder);
        }

        if (null != produceSn && null != workCell) {
            MesQueueOrder queueOrder = produceSnExtService.getQueueOrder(organizeCode, workCell.getWorkCenterCode(), workCell.getWorkCellCode(), produceSn.getProductSn());
            if (null == queueOrder) resultMap.put(MesPcnExtConstWords.MESSAGE, String.format("请检查工位队列信息,客户条码[%s]加工单[%s]工位队列信息不存在!", produceSn.getCustSn(), produceSn.getWorkOrderNo()));
            else resultMap.put(MesQueueOrder.class.getSimpleName(), queueOrder);
        }

        return resultMap;
    }

    @Override
    public BaseBean getWorkOrderSort(String organizeCode, String sn, Boolean isBackOrder) {
        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(sn) || StringUtils.isEmpty(isBackOrder)) return null;
        return isBackOrder ? getWorkOrderSort2Order(organizeCode, sn) : getWorkOrderSort2Ps(organizeCode, sn);
    }

    @Override
    public void updateMesWorkOrderOrderStatusShippingByWorkOrderNo(String organizeCode, List<String> workOrderNoList, String userName) {
        if (StringUtils.isEmpty(organizeCode) || CollectionUtils.isEmpty(workOrderNoList)) return;
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        if (workOrderNoList.size() == MesPcnExtConstWords.ONE) {
            DdlPreparedPack.getStringEqualPack(workOrderNoList.iterator().next(), MesPcnExtConstWords.WORK_ORDER_NO, packBean);
        } else {
            DdlPreparedPack.getInPackList(workOrderNoList, MesPcnExtConstWords.WORK_ORDER_NO, packBean);
        }
        workOrderRepository.updateByProperties(
                new String[]{MesPcnExtConstWords.MODIFY_USER, MesPcnExtConstWords.MODIFY_DATE_TIME, MesPcnExtConstWords.SYSTEM_SYNC_STATUS, MesPcnExtConstWords.WORK_ORDER_STATUS, MesPcnExtConstWords.SHIPPING_TIME},
                new Object[]{userName, (new SimpleDateFormat(MesPcnExtConstWords.DATE_FORMAT_SSS)).format(new Date()), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), MesExtEnumUtil.ORDER_STATUS.SHIPPING.getValue(), TimeTool.getNowTime(true)}, packBean);
    }

    private MesWorkOrder getWorkOrderSort2Order(String organizeCode, String sn) {
        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(sn)) return null;
        MesProduceSn produceSn;
        MesWorkOrder workOrder = null;
        if (sn.length() == MesPcnExtConstWords.CUSTOMER_SN_LENGTH_GM) {
            produceSn = produceSnExtService.getProduceSnByCustSn(organizeCode, customerSnTransformService.transformBarCodeGm(sn));
            if (null != produceSn && !StringUtils.isEmpty(produceSn.getWorkOrderNo())) workOrder = getWorkOrder(organizeCode, produceSn.getWorkOrderNo());
        } else {
            produceSn = produceSnExtService.getProduceSn(organizeCode, sn, sn);
            if (null == produceSn) produceSn = produceSnExtService.getProduceSnByCustSn(organizeCode, sn);
            if (null != produceSn && !StringUtils.isEmpty(produceSn.getWorkOrderNo())) workOrder = getWorkOrder(organizeCode, produceSn.getWorkOrderNo());
        }
        return workOrder;
    }

    private MesProduceSn getWorkOrderSort2Ps(String organizeCode, String sn) {
        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(sn)) return null;
        MesProduceSn produceSn;
        if (sn.length() == MesPcnExtConstWords.CUSTOMER_SN_LENGTH_GM) {
            produceSn = produceSnExtService.getProduceSnByCustSn(organizeCode, customerSnTransformService.transformBarCodeGm(sn));
        } else {
            produceSn = produceSnExtService.getProduceSn(organizeCode, sn, sn);
            if (null == produceSn) produceSn = produceSnExtService.getProduceSnByCustSn(organizeCode, sn);
        }
        return produceSn;
    }

    @Override
    public Map<String, Double> getControlOrderQtyMap(String organizeCode, String workCenterCode, List<String> partNoList, String startTime, String endTime) {
        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(workCenterCode) ||
                StringUtils.isEmpty(startTime) || StringUtils.isEmpty(endTime) || CollectionUtils.isEmpty(partNoList)) return null;
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.timeBuilder(startTime, endTime, MesPcnExtConstWords.PLAN_START_TIME, packBean, false);
        DdlPreparedPack.getStringEqualPack(workCenterCode, MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
        if (partNoList.size() == 1) DdlPreparedPack.getStringEqualPack(partNoList.get(0), MesPcnExtConstWords.PART_NO, packBean);
        else DdlPreparedPack.getInPackList(partNoList, MesPcnExtConstWords.PART_NO, packBean);
        List<MesWorkOrder> workOrderList = workOrderRepository.findByHqlWhere(packBean);
        workOrderList = CollectionUtils.isEmpty(workOrderList) ? null :
                workOrderList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getPartNo()) && !StringUtils.isEmpty(o.getWorkOrderStatus()) && !StringUtils.isEmpty(o.getOrderFlag())
                        && o.getWorkOrderStatus().compareTo(MesExtEnumUtil.ORDER_STATUS.CREATE.getValue()) != 0 && !o.getOrderFlag().equals(MesExtEnumUtil.ORDER_TYPE_IDENTIFICATION.P.getValue()))).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(workOrderList)) return null;
        Map<String, List<MesWorkOrder>> workOrderMap = workOrderList.stream().filter(o -> null != o).collect(Collectors.groupingBy(o -> o.getPartNo().toUpperCase()));

        Map<String, Double> controlOrderQtyMap = new HashMap<>();
        Double qty;
        for (Map.Entry<String, List<MesWorkOrder>> entry : workOrderMap.entrySet()) {
            if (null == entry) continue;
            qty = new Double(MesPcnExtConstWords.ZERO);
            for (MesWorkOrder workOrder : entry.getValue()) {
                if (null == workOrder) continue;
                qty = MathOperation.add(qty, workOrder.getWorkOrderStatus().compareTo(MesExtEnumUtil.ORDER_STATUS.CLOSE.getValue()) >= 0 ? workOrder.getCompleteQty() : workOrder.getQty());
            }
            controlOrderQtyMap.put(entry.getKey(), qty);
        }
        return controlOrderQtyMap;
    }

    @Override
    public Map<String, Double> getCompleteOrderQtyMap(String organizeCode, String workCenterCode, List<String> partNoList, String lotNo) {
        if (StringUtils.isEmpty(organizeCode) || StringUtils.isEmpty(workCenterCode) || StringUtils.isEmpty(lotNo) || CollectionUtils.isEmpty(partNoList)) return null;
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(lotNo, MesPcnExtConstWords.LOT_NO, packBean);
        DdlPreparedPack.getStringEqualPack(workCenterCode, MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
        if (partNoList.size() == 1) DdlPreparedPack.getStringEqualPack(partNoList.get(0), MesPcnExtConstWords.PART_NO, packBean);
        else DdlPreparedPack.getInPackList(partNoList, MesPcnExtConstWords.PART_NO, packBean);
        List<MesWorkOrderControlQtyRecord> workOrderControlQtyRecordList = workOrderControlQtyRecordRepository.findByHqlWhere(packBean);
        return CollectionUtils.isEmpty(workOrderControlQtyRecordList) ? null :
                workOrderControlQtyRecordList.stream().filter(o -> null != o).collect(Collectors.groupingBy(o -> o.getPartNo().toUpperCase(), Collectors.summingDouble(MesWorkOrderControlQtyRecord::getQty)));
    }

}
