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

import cn.estsh.i3plus.ext.mes.pcn.api.base.IQualityDecisionService;
import cn.estsh.i3plus.ext.mes.pcn.api.base.ISxRepairWorkService;
import cn.estsh.i3plus.ext.mes.pcn.api.base.IWorkCenterExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IProduceSnExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IProduceSnRepairService;
import cn.estsh.i3plus.ext.mes.pcn.pojo.bean.*;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.RepairRequestModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.repository.*;
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.platform.common.convert.ConvertBean;
import cn.estsh.i3plus.platform.common.exception.ImppExceptionEnum;
import cn.estsh.i3plus.platform.common.tool.MathOperation;
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.*;
import cn.estsh.impp.framework.boot.exception.ImppExceptionBuilder;
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.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author: Wynne.Lu
 * @CreateDate: 2019/8/30 1:39 PM
 * @Description:
 **/
@Service
public class QualityDecisionService implements IQualityDecisionService {

    @Autowired
    private IProduceSnExtService produceSnExtService;

    @Autowired
    private IProduceSnRepairService produceSnRepairService;

    @Autowired
    private MesProduceSnExtRepository produceSnExtRepository;

    @Autowired
    private MesDefectRepository mesDefectRDao;

    @Autowired
    private MesTypeCfgRepository typeCfgRepository;

    @Autowired
    private MesBadCellRepository badCellRepository;

    @Autowired
    private MesBadCellDetailRepository mesBadCellDetailRDao;

    @Autowired
    private MesProcessRepository mesProcessRDao;

    @Autowired
    private IWorkCenterExtService workCenterExtService;

    @Autowired
    private ISxRepairWorkService repairWorkService;

    @Autowired
    private MesProcessCellRepository mesProcessCellRDao;

    @Autowired
    private MesProduceSnMcRecordRepository produceSnMcRecordRepository;

    @Autowired
    private MesBadCellDetailRepository badCellDetailRepository;

    @Autowired
    private MesRepairRecordExtRepository repairRecordExtRepository;

    @Override
    public Map<String, Object> doCheckSerialNumberExt(String serialNumber, String organizeCode, String workCenterCode) {

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

        MesProduceSnExt produceSnExt = doCheckSerialNumber(serialNumber, organizeCode, workCenterCode);

        if (produceSnExt.getOperateType() == MesPcnExtEnumUtil.SN_OPERATE_TYPE.REPAIR.getValue()) {
            resultMap.put("isFreeze", false);
        } else {
            resultMap.put("isFreeze", false);
        }

        resultMap.put("object", produceSnExt);

        return resultMap;
    }

    @Override
    public MesProduceSnExt doCheckSerialNumber(String serialNumber, String organizeCode, String workCenterCode) {

        MesProduceSnMcRecord produceSnMcRecordDb = produceSnMcRecordRepository.getByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.MANAGE_CODE, MesPcnExtConstWords.SN_STATUS},
                new Object[]{organizeCode, CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), serialNumber, MesPcnExtEnumUtil.MC_RECORD_SN_STATUS.LINE_ON.getValue()});

        MesProduceSnExt produceSnExt = null;
        if(produceSnMcRecordDb != null){

            produceSnExt = produceSnExtService.getProduceSnExtBySn(organizeCode, produceSnMcRecordDb.getSerialNumber());

        }

        if(produceSnExt == null){

            MesProduceSnRepair produceSnRepair = produceSnRepairService.getProduceSnRepairBySn(organizeCode, serialNumber);

            if (produceSnRepair == null) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                        .setErrorDetail("条码信息不存在，请检查")
                        .build();
            }

            if (!StringUtils.isEmpty(produceSnRepair.getOutWorkCenterTime())) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                        .setErrorDetail("扫描的条码的条码状态为【下线】，不可以操作", produceSnRepair.getSerialNumber())
                        .build();
            }

            if(null != produceSnRepair && !workCenterCode.equals(produceSnRepair.getWorkCenterCode())){
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                        .setErrorDetail("当前扫描的条码[%s]的产线为[%s]，与当前选择的产线[%s]不一致，请重新扫描", serialNumber,produceSnRepair.getWorkCenterCode(), workCenterCode)
                        .build();
            }

            produceSnExt = produceSnExtService.getProduceSnExtBySn(organizeCode, produceSnRepair.getSerialNumber());

        } else {
            if(produceSnExt.getSnStatus() == MesPcnExtEnumUtil.PRODUCE_SN_STATUS.OFFLINE.getValue()){
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                        .setErrorDetail("扫描的条码的条码状态为【下线】，不可以操作")
                        .build();

            }

            // 先查询条码信息，判断最终工单号字段与工单号字段是否一致，一致的话判断生产线跟条码信息的生产线是否一致,工单不一样的话，根据最终工单号与条码查询返工条码表，判断生产线是否一致
            if (produceSnExt.getLastWorkOrderNo().equals(produceSnExt.getWorkOrderNo())) {
                if (!workCenterCode.equals(produceSnExt.getWorkCenterCode())) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                            .setErrorDetail("当前扫描的条码[%s]的产线为[%s]，与当前选择的产线[%s]不一致，请重新扫描", serialNumber, produceSnExt.getWorkCenterCode(), workCenterCode)
                            .build();
                }
            } else {
                MesProduceSnRepair produceSnRepair = produceSnRepairService.getProduceSnRepairBySnAndOrderNo(organizeCode, serialNumber, produceSnExt.getLastWorkOrderNo());

                if (produceSnRepair == null) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                            .setErrorDetail("条码信息不存在，请检查")
                            .build();
                }

                if (null != produceSnRepair && !workCenterCode.equals(produceSnRepair.getWorkCenterCode())) {
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                            .setErrorDetail("当前扫描的条码[%s]的产线为[%s]，与当前选择的产线[%s]不一致，请重新扫描", serialNumber,produceSnRepair.getWorkCenterCode(), workCenterCode)
                            .build();
                }
            }
        }

        return produceSnExt;
    }

    @Override
    public Map<String,List<MesDefect>> findMesDefect(String organizeCode) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(organizeCode, MesPcnExtConstWords.ORGANIZE_CODE, packBean);
        List<MesDefect> mesDefects = mesDefectRDao.findByHqlWhere(packBean);

        if(CollectionUtils.isEmpty(mesDefects)){
            return new HashMap<>();
        }

        List<MesTypeCfg> typeCfgList = typeCfgRepository.findByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, "typeCode"},
                new Object[]{organizeCode, CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(),
                        CommonEnumUtil.IS_VAILD.VAILD.getValue(), MesPcnExtEnumUtil.MES_TYPE_CFG_EXT.BAD.getValue()});
        Map<String, List<MesTypeCfg>> typeCfgMap = CollectionUtils.isEmpty(typeCfgList) ? null :
                typeCfgList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getTypeCode()))).collect(Collectors.groupingBy(MesTypeCfg::getBusinessTypeCode));
        for (MesDefect defectDb : mesDefects) {
            List<MesTypeCfg> typeCfgs = CollectionUtils.isEmpty(typeCfgMap) ? null : typeCfgMap.get(defectDb.getDefectType());
            defectDb.setDefectTypeName(CollectionUtils.isEmpty(typeCfgs) ? null : typeCfgs.get(0).getBusinessTypeName());
        }

        Map<String,List<MesDefect>> mesDefectMap = mesDefects.stream().collect(Collectors.groupingBy(q -> q.getDefectType() + "&&" + q.getDefectTypeName()));

        return mesDefectMap;
    }

    @Override
    public void insertMesBadCellAndDetail(RepairRequestModel repairRequestModel) {
        List<MesBadCellDetail> badCellDetailList = repairRequestModel.getMesDefectRecordList();
        if (CollectionUtils.isEmpty(badCellDetailList)) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("入参缺少不良明细数据")
                    .build();
        }
        String workOrderNo;

        MesProduceSnExt produceSnExt = doCheckSerialNumber(repairRequestModel.getSerialNumber(), repairRequestModel.getOrganizeCode(), repairRequestModel.getWorkCenterCode());

        if (!StringUtils.isEmpty(produceSnExt.getLastWorkOrderNo()) && !produceSnExt.getLastWorkOrderNo().equals(produceSnExt.getWorkOrderNo())) {
            workOrderNo = produceSnExt.getLastWorkOrderNo();
        } else {
            workOrderNo = produceSnExt.getWorkOrderNo();
        }

        MesWorkCenterExt workCenterExt = workCenterExtService.getWorkCenterExtByWorkCenterCode(repairRequestModel.getOrganizeCode(), repairRequestModel.getWorkCenterCode());
        if (null == workCenterExt) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("生产线代码[%s]无效", repairRequestModel.getWorkCenterCode())
                    .build();
        }
        if (StringUtils.isEmpty(workCenterExt.getShiftCode()) || StringUtils.isEmpty(workCenterExt.getWorkTime())) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("生产线[%s]未启动班次", repairRequestModel.getWorkCenterCode())
                    .build();
        }

        MesBadCell mesBadCell = badCellRepository.getByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID,
                        MesPcnExtConstWords.WORK_ORDER_NO, MesPcnExtConstWords.WORK_TIME, MesPcnExtConstWords.SHIFT_CODE, MesPcnExtConstWords.WORK_CELL_CODE},
                new Object[]{repairRequestModel.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(),
                        workOrderNo, workCenterExt.getWorkTime(), workCenterExt.getShiftCode(), repairRequestModel.getWorkCellCode()});

        if(mesBadCell == null){
            MesProcess processDb = mesProcessRDao.getByProperty(
                    new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.PROCESS_CODE},
                    new Object[]{repairRequestModel.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue(), repairRequestModel.getProcessCode()});
            mesBadCell = new MesBadCell();
            mesBadCell.setOrganizeCode(repairRequestModel.getOrganizeCode());
            mesBadCell.setPartNo(produceSnExt.getPartNo());
            mesBadCell.setPartNameRdd(produceSnExt.getPartNameRdd());
            mesBadCell.setWorkCenterCode(repairRequestModel.getWorkCenterCode());
            mesBadCell.setWorkCellCode(repairRequestModel.getWorkCellCode());
            mesBadCell.setProcessCode(repairRequestModel.getProcessCode());
            mesBadCell.setProcessNameRdd(null != processDb ? processDb.getProcessName() : null);
            mesBadCell.setQty(new Double(badCellDetailList.size()));
            mesBadCell.setWorkOrderNo(workOrderNo);
            mesBadCell.setWorkTime(workCenterExt.getWorkTime());
            mesBadCell.setShiftCode(workCenterExt.getShiftCode());
            ConvertBean.serviceModelInitialize(mesBadCell, repairRequestModel.getModifyUser());
            badCellRepository.insert(mesBadCell);
        }else {
            mesBadCell.setQty(MathOperation.add(mesBadCell.getQty(), new Double(badCellDetailList.size())));
            ConvertBean.serviceModelUpdate(mesBadCell, repairRequestModel.getModifyUser());
            badCellRepository.save(mesBadCell);
        }

        //新增不良明细数据
        MesBadCellDetail badCellDetail;
        for(MesBadCellDetail mesBadCellDetail : badCellDetailList){
            badCellDetail = new MesBadCellDetail();
            BeanUtils.copyProperties(mesBadCellDetail, badCellDetail, MesPcnExtConstWords.ID);
            badCellDetail.setWorkTime(workCenterExt.getWorkTime());
            badCellDetail.setShiftCode(workCenterExt.getShiftCode());
            badCellDetail.setSerialNumber(repairRequestModel.getSerialNumber());
            badCellDetail.setWorkCellCode(repairRequestModel.getWorkCellCode());
            badCellDetail.setRepairStatus(MesPcnExtEnumUtil.MES_REPAIR_STATUS.NO_REPAIR.getValue());
            badCellDetail.setApprovalStatus(MesPcnExtEnumUtil.BAD_CELL_DETAIL_APPROVAL_STATUS.UN_APPROVAL.getValue());
            ConvertBean.serviceModelInitialize(badCellDetail, repairRequestModel.getModifyUser());
            badCellDetail.setDefectActionTime(badCellDetail.getCreateDatetime());
            mesBadCellDetailRDao.insert(badCellDetail);
        }

        produceSnExt.setQcStatus(MesPcnExtEnumUtil.PRODUCE_SN_QC_STATUS.DEFECTED.getValue());
        ConvertBean.serviceModelUpdate(produceSnExt, repairRequestModel.getModifyUser());
        produceSnExt.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        new ConvertBeanExt(produceSnExt).convertBean(produceSnExt);
        produceSnExtRepository.save(produceSnExt);
    }

    @Override
    public void doUnfreeze(RepairRequestModel repairRequestModel) {

        MesProduceSnExt produceSnExt = doCheckSerialNumber(repairRequestModel.getSerialNumber(), repairRequestModel.getOrganizeCode(), repairRequestModel.getWorkCenterCode());

        List<MesBadCellDetail> badCellDetailList = repairWorkService.getMesBadCellDetailBySerialNumber(produceSnExt.getSerialNumber(), repairRequestModel.getOrganizeCode());

        boolean isCompleteRepair =  CollectionUtils.isEmpty(badCellDetailList) ? false : badCellDetailList.stream().filter(o -> o.getRepairStatus() == MesPcnExtEnumUtil.MES_REPAIR_STATUS.REPAIRED.getValue()).collect(Collectors.toList()).size() > 0 ;

        if (produceSnExt.getSnStatus() != MesPcnExtEnumUtil.PRODUCE_SN_STATUS.PROCESS.getValue()) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("当前条码状态为[%s],不为[%s]", MesPcnExtEnumUtil.PRODUCE_SN_STATUS.valueOfDescription(produceSnExt.getSnStatus()), MesPcnExtEnumUtil.PRODUCE_SN_STATUS.PROCESS.getDescription())
                    .build();
        }

        if (produceSnExt.getQcStatus() != MesPcnExtEnumUtil.PRODUCE_SN_QC_STATUS.DEFECTED.getValue()) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("当前条码状态为[%s],不为[%s]", MesPcnExtEnumUtil.PRODUCE_SN_STATUS.valueOfDescription(produceSnExt.getSnStatus()), MesPcnExtEnumUtil.PRODUCE_SN_STATUS.PROCESS.getDescription())
                    .build();
        }

        if (!isCompleteRepair) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("未维修完成")
                    .build();
        }

        produceSnExt.setOperateType(MesPcnExtEnumUtil.SN_OPERATE_TYPE.QUALIFIED.getValue());
        produceSnExt.setQcStatus(MesPcnExtEnumUtil.PRODUCE_SN_QC_STATUS.QUALIFIED.getValue());
        ConvertBean.serviceModelUpdate(produceSnExt, repairRequestModel.getModifyUser());
        new ConvertBeanExt(produceSnExt).convertBean(produceSnExt);
        produceSnExtRepository.save(produceSnExt);

        List<MesBadCellDetail> badCellDetailBySerialNumberList = repairWorkService.getMesBadCellDetailBySerialNumber(produceSnExt.getSerialNumber(), produceSnExt.getOrganizeCode());

        List<MesRepairRecordExt> repairRecordBySerialNumberList = repairWorkService.getMesRepairRecordBySerialNumber(produceSnExt.getSerialNumber(), produceSnExt.getOrganizeCode());

        if (!CollectionUtils.isEmpty(badCellDetailBySerialNumberList)) {
            for (MesBadCellDetail badCellDetail : badCellDetailBySerialNumberList) {
                badCellDetail.setIsFreeze(MesPcnExtEnumUtil.IS_UNFREEZE.BIND.getValue());
                ConvertBean.serviceModelUpdate(badCellDetail, repairRequestModel.getModifyUser());
            }

            badCellDetailRepository.saveAll(badCellDetailBySerialNumberList);
        }

        if (!CollectionUtils.isEmpty(repairRecordBySerialNumberList)) {
            for (MesRepairRecordExt repairRecordExt : repairRecordBySerialNumberList) {
                repairRecordExt.setIsFreeze(MesPcnExtEnumUtil.IS_UNFREEZE.BIND.getValue());
                ConvertBean.serviceModelUpdate(repairRecordExt, repairRequestModel.getModifyUser());
            }

            repairRecordExtRepository.saveAll(repairRecordBySerialNumberList);
        }



    }

    @Override
    public MesProcessCell getMesProcessCell(String workCenterCode, String workCellCode, String organizeCode) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(workCenterCode, MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(workCellCode, MesPcnExtConstWords.WORK_CELL_CODE, packBean);
        return mesProcessCellRDao.getByProperty(packBean);
    }

}
