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

import cn.estsh.i3plus.ext.mes.pcn.api.base.IPartExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.base.ISxWorkOrderExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IOqcManageService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IPackageExtService;
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.apiservice.dao.IOutPutStatisticsDao;
import cn.estsh.i3plus.ext.mes.pcn.apiservice.dao.IPackageExtDao;
import cn.estsh.i3plus.ext.mes.pcn.apiservice.dao.IProduceSnRepairDao;
import cn.estsh.i3plus.ext.mes.pcn.pojo.bean.*;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.*;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.bu.BuOutPutStatisticsModel;
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.MesPcnExtConstWords;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtEnumUtil;
import cn.estsh.i3plus.mes.pcn.api.iservice.busi.ISyncFuncService;
import cn.estsh.i3plus.platform.common.convert.ConvertBean;
import cn.estsh.i3plus.platform.common.exception.ImppExceptionEnum;
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.tool.DdlPreparedPack;
import cn.estsh.i3plus.pojo.mes.model.GenSerialNoModel;
import cn.estsh.impp.framework.boot.exception.ImppExceptionBuilder;
import cn.estsh.impp.framework.boot.util.ImppRedis;
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.util.*;

/**
 * @author wangjie
 * @version 1.0
 * @date 2021/1/13 9:28
 *
 * 成品：
 * 1.日常&拆机&空洞：抽检数量=1，批次范围(日常=拆机),必须先做日常||空洞,才能做拆机
 * 2.一个条码日常||空洞跟拆机都只能做一次，批次范围内的条码不能再生成单据
 * 3.新产量数据时批次范围内有未关联完成的单据时不能再生成日常或拆机单据
 * 4.日常&拆机&空洞:新产量数据时,批次范围可大于产量,但要小于剩余批次,   剩余批次=计划数量-(汇总旧产量数据的产量+新产量数据的批次范围)
 *                旧产量数据时,批次范围小于剩余批次,    剩余批次=此产量数据的产量-此产量数据批次范围
 * 5.新产量数据时判断旧产量数据是否存在批次范围大于产量的 改成等于产量, 总单据批次范围也需要调整
 *
 * 组件：
 * 1.组件不做拆机
 * 2.日常跟空洞,一个工单只能生成一个类型的单据,有单据未点结果则不能再生成
 * 3.日常&空洞:新产量数据时,批次范围可大于产量,但要小于剩余批次,   剩余批次=计划数量-(汇总旧产量数据的产量+新产量数据的批次范围)
 *            旧产量数据时,批次范围小于剩余批次,    剩余批次=此产量数据的产量-此产量数据批次范围
 * 4.新产量数据时判断旧产量数据是否存在批次范围大于产量的 改成等于产量, 总单据批次范围也需要调整
 *
 **/
@Slf4j
@Service
public class OqcManageService implements IOqcManageService {

    @Autowired
    private MesOutPutStatisticsRepository outPutStatisticsRepository;

    @Autowired
    private MesOutPutStatisticsOqcRepository outPutStatisticsOqcRepository;

    @Autowired
    private MesOqcCheckRepository oqcCheckRepository;

    @Autowired
    private SxOqcCheckRepository sxOqcCheckRepository;

    @Autowired
    private MesOqcCheckDetailRepository oqcCheckDetailRepository;

    @Autowired
    private MesOqcProjectRepository oqcProjectRepository;

    @Autowired
    private MesOqcPackageDetailRepository oqcPackageDetailRepository;

    @Autowired
    private SxOqcSingleRepository sxOqcSingleRepository;

    @Autowired
    private SxOqcBatchRepository sxOqcBatchRepository;

    @Autowired
    private IPartExtService partExtService;

    @Autowired
    private ISxWorkOrderExtService workOrderExtService;

    @Autowired
    private IPackageExtService packageExtService;

    @Autowired
    private IProduceSnExtService produceSnExtService;

    @Autowired
    private IPackageExtDao packageExtDao;

    @Autowired
    private IProduceSnRepairDao produceSnRepairDao;

    @Autowired
    private IProduceSnRepairService produceSnRepairService;

    @Autowired
    private ISyncFuncService syncFuncService;

    @Autowired
    private IOutPutStatisticsDao outPutStatisticsDao;

    @Autowired
    private MesErrorLineOffRepository errorLineOffRepository;

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

    @Override
    public ListPager<MesOqcCheckDetail> queryOqcDetail(String organizeCode, String oqcNo, Pager pager) {
        DdlPackBean hqlPack = MesPcnExtHqlPack.getOqcCheckDetail(organizeCode, oqcNo);
        pager = PagerHelper.getPager(pager, oqcCheckDetailRepository.findByHqlWhereCount(hqlPack));
        hqlPack.setOrderByStr(" order by seq asc ");
        return new ListPager(oqcCheckDetailRepository.findByHqlWherePage(hqlPack, pager), pager);
    }

    private Boolean compareString(String str1, String str2) {
        if (StringUtils.isEmpty(str1)) {
            str1 = "null";
        }
        if (StringUtils.isEmpty(str2)) {
            str2 = "null";
        }
        if (str1.equals(str2)) {
            return true;
        } else {
            return false;
        }
    }

    private Boolean compareDouble(Double dou1, Double dou2) {
        if (StringUtils.isEmpty(dou1)) {
            dou1 = new Double(0);
        }
        if (StringUtils.isEmpty(dou2)) {
            dou2 = new Double(0);
        }
        if (dou1.compareTo(dou2) == 0) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public OqcManageModel resetOqcData(OqcManageModel model) {

        String key = new StringJoiner(MesPcnExtConstWords.COLON).add(model.getOrganizeCode()).add(MesPcnExtConstWords.OQC_MANAGE_DATA).toString();
        redisMesPcn.deleteHash(key, model.getUserId());

        Map<Integer, Boolean> spotCheckQtyReadOnlyMap = new HashMap<>();
        spotCheckQtyReadOnlyMap.put(10, true);
        spotCheckQtyReadOnlyMap.put(20, true);
        spotCheckQtyReadOnlyMap.put(30, true);

        Map<Integer, Boolean> batchLimitReadOnlyMap = new HashMap<>();
        batchLimitReadOnlyMap.put(10, true);
        batchLimitReadOnlyMap.put(20, true);
        batchLimitReadOnlyMap.put(30, true);

        Map<Integer, Boolean> genOqcReadOnlyMap = new HashMap<>();
        genOqcReadOnlyMap.put(10, true);
        genOqcReadOnlyMap.put(20, true);
        genOqcReadOnlyMap.put(30, true);

        Map<Integer, Double> batchLimitMap = new HashMap<>();
        batchLimitMap.put(10, new Double(1));
        batchLimitMap.put(20, new Double(1));
        batchLimitMap.put(30, new Double(1));

        OqcManageModel result = new OqcManageModel();
        result.setBatchLimitMap(batchLimitMap);
        result.setSpotCheckQtyReadOnlyMap(spotCheckQtyReadOnlyMap);
        result.setBatchLimitReadOnlyMap(batchLimitReadOnlyMap);
        result.setGenOqcReadOnlyMap(genOqcReadOnlyMap);
        return result;
    }

    private String getOqcNo(String userName, String organizeCode) {
        BaseResultBean oneCodeResult = syncFuncService.syncSerialNo(new GenSerialNoModel(MesPcnExtEnumUtil.COMMON_SN.OQC_NO.getCode()), userName, organizeCode, 1);
        if (oneCodeResult != null && oneCodeResult.isSuccess()) {
            return oneCodeResult.getResultList().get(0).toString();
        } else {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.CLOUD_CALL_EXCEPTION.getCode())
                    .setErrorDetail("生成唯一单号失败")
                    .build();
        }
    }

    @Override
    public ListPager<OqcLastCheckModel> queryOqcLastCheckPager(OqcLastCheckModel model, Pager pager) {
        pager = PagerHelper.getPager(pager, outPutStatisticsDao.queryOutPutStatisticsOqcByPagerCount(model));
        List<OqcLastCheckModel> modelList = outPutStatisticsDao.queryOutPutStatisticsOqcByPager(model , pager);
        //if (!CollectionUtils.isEmpty(modelList)) {
        //    List<String> partNoList = (modelList.stream().filter(o -> null != o).map(OqcLastCheckModel::getPartNo).collect(Collectors.toList()))
        //            .stream().distinct().filter(o -> !StringUtils.isEmpty(o)).collect(Collectors.toList());
        //    List<MesPartExt> partExtList = partExtService.getPartExtListByPartNoList(model.getOrganizeCode(), partNoList);
        //    Map<String, List<MesPartExt>> partNoMap = CollectionUtils.isEmpty(partExtList) ? new HashMap<>() :
        //            partExtList.stream().filter(o -> null != o).collect(Collectors.groupingBy(MesPartExt::getPartNo));
        //
        //    for (OqcLastCheckModel oqcLastCheckModel : modelList) {
        //        if (null != oqcLastCheckModel) {
        //            if (StringUtils.isEmpty(oqcLastCheckModel.getCheckResult()) ||
        //                    MesPcnExtEnumUtil.OQC_TOTAL_STATUS.UNTREATED.getValue() == oqcLastCheckModel.getCheckResult() ||
        //                    StringUtils.isEmpty(MesPcnExtEnumUtil.OQC_TOTAL_STATUS.valueOfDescription(oqcLastCheckModel.getCheckResult()))) {
        //                oqcLastCheckModel.setColor("white");
        //            } else if (MesPcnExtEnumUtil.OQC_TOTAL_STATUS.QUALIFIED.getValue() == oqcLastCheckModel.getCheckResult()) {
        //                oqcLastCheckModel.setColor("green");
        //            } else {
        //                oqcLastCheckModel.setColor("red");
        //            }
        //
        //            oqcLastCheckModel.setCheckResultName(MesPcnExtEnumUtil.OQC_TOTAL_STATUS.valueOfDescription(oqcLastCheckModel.getCheckResult()));
        //            if (partNoMap.containsKey(oqcLastCheckModel.getPartNo()) &&
        //                    !StringUtils.isEmpty(partNoMap.get(oqcLastCheckModel.getPartNo()).get(0).getCategoryCode2())) {
        //                oqcLastCheckModel.setZjCheckReadOnly(false);
        //            } else {
        //                oqcLastCheckModel.setZjCheckReadOnly(true);
        //            }
        //        }
        //    }
        //}
        return new ListPager(modelList, pager);
    }

    @Override
    public void updateOutPutStatisticsOqcCheck(OqcLastCheckParamModel model) {
        for (OqcLastCheckParamModel item : model.getModelList()) {
            MesOutPutStatisticsOqc oqc = outPutStatisticsOqcRepository.getById(item.getId());
            oqc.setCheckResult(model.getCheckResult());
            oqc.setCheckUser(model.getUserInfo());
            oqc.setRemark(item.getRemark());
            oqc.setCheckNo(getTotalOqcNo(model.getUserInfo(), model.getOrganizeCode()));
            ConvertBean.serviceModelUpdate(oqc, model.getUserInfo());
            oqc.setConfirmTime(oqc.getModifyDatetime());
            oqc.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            outPutStatisticsOqcRepository.save(oqc);

            SxOqcBatch sxOqcBatch = new SxOqcBatch();
            sxOqcBatch.setWorkTime(oqc.getWorkTime());
            sxOqcBatch.setShiftCode(oqc.getShiftCode());
            sxOqcBatch.setWorkOrderNo(oqc.getWorkOrderNo());
            sxOqcBatch.setCheckResult(oqc.getCheckResult());
            sxOqcBatch.setSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            sxOqcBatch.setOrganizeCode(model.getOrganizeCode());
            ConvertBean.serviceModelInitialize(sxOqcBatch, model.getUserInfo());
            sxOqcBatchRepository.insert(sxOqcBatch);
        }
    }

    private String getTotalOqcNo(String userName, String organizeCode) {
        BaseResultBean oneCodeResult = syncFuncService.syncSerialNo(new GenSerialNoModel(MesPcnExtEnumUtil.COMMON_SN.TOQC_NO.getCode()), userName, organizeCode, 1);
        if (oneCodeResult != null && oneCodeResult.isSuccess()) {
            return oneCodeResult.getResultList().get(0).toString();
        } else {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.CLOUD_CALL_EXCEPTION.getCode())
                    .setErrorDetail("生成唯一工单号失败")
                    .build();
        }
    }

    @Override
    public MissPartConfirmModel queryMissingPart(String serialNumber, String organizeCode, Pager pager) {
        MissPartConfirmModel missPartConfirm = getMissPartConfirm( serialNumber, organizeCode );
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(missPartConfirm.getOrderNo(), MesPcnExtConstWords.WORK_ORDER_NO, packBean);
        DdlPreparedPack.getOrderByPack(new Object[]{CommonEnumUtil.ASC_OR_DESC.ASC.getValue()}, new String[]{MesPcnExtConstWords.SERIAL_NUMBER}, packBean);
        pager = PagerHelper.getPager(pager, errorLineOffRepository.findByHqlWhereCount(packBean));
        List<MesErrorLineOff> missPartList = errorLineOffRepository.findByHqlWherePage(packBean, pager);
        if (CollectionUtils.isEmpty(missPartList)) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                    .setErrorDetail("产品条码[%s]关联的生产工单[%s]不存在缺件数据", serialNumber, missPartConfirm.getOrderNo())
                    .build();
        }

        missPartConfirm.setMesErrorLineOffs(new ListPager(missPartList, pager));
        return missPartConfirm;
    }

    @Override
    public void updateErrorLineOff(Long[] idsStr, String organizeCode, String userInfo) {
        if (null == idsStr) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("请选勾选缺件数据")
                    .build();
        }

        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getInPackArray(idsStr, MesPcnExtConstWords.ID, packBean);
        List<MesErrorLineOff> errorLineOffList = errorLineOffRepository.findByHqlWhere(packBean);
        if (CollectionUtils.isEmpty(errorLineOffList)) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                    .setErrorDetail("选择的数据不存在")
                    .build();
        }

        for (MesErrorLineOff errorLineOff : errorLineOffList) {
            if (null == errorLineOff) {
                continue;
            }
            if (CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue() == errorLineOff.getFreStatus() ||
                    CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue() == errorLineOff.getConfirmStatus()) {
                continue;
            }
            errorLineOff.setConfirmStatus(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue());
            ConvertBean.serviceModelUpdate(errorLineOff, userInfo);
            errorLineOff.setConfirmTime(errorLineOff.getModifyDatetime());
            errorLineOff.setConfirmUser(userInfo);
            errorLineOffRepository.save(errorLineOff);
        }
    }

    @Override
    public MissPartConfirmModel getMissingPartAndWorkOrderBySn(String serialNumber, String organizeCode) {
        return getMissPartConfirm(serialNumber, organizeCode);
    }

    @Override
    public List<BuOutPutStatisticsModel> queryOutPutStatisticsModelList(OqcLastCheckModel model, String organizeCode) {
        List<MesOutPutStatistics> mesOutPutStatistics = queryOutPutStatisticsList(model, organizeCode);
        List<BuOutPutStatisticsModel> outPutStatisticsModels = new ArrayList<>();
        mesOutPutStatistics.stream().forEach(outPutStatistics -> {
            BuOutPutStatisticsModel outPutStatisticsModel = new BuOutPutStatisticsModel();
            BeanUtils.copyProperties(outPutStatistics, outPutStatisticsModel);
            outPutStatisticsModels.add(outPutStatisticsModel);
        });
        return outPutStatisticsModels;
    }

    @Override
    public List<MesOutPutStatistics> queryOutPutStatisticsList(OqcLastCheckModel model, String organizeCode) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(model.getWorkCenterCode(), MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(model.getPartNo(), MesPcnExtConstWords.PART_NO, packBean);
        DdlPreparedPack.getStringEqualPack(model.getWorkOrderNo(), MesPcnExtConstWords.WORK_ORDER_NO, packBean);
        DdlPreparedPack.getStringEqualPack(model.getShiftCode(), MesPcnExtConstWords.SHIFT_CODE, packBean);
        DdlPreparedPack.timeBuilder(model.getWorkTimeStart(), model.getWorkTimeEnd(), MesPcnExtConstWords.WORK_TIME, packBean, false);
        return outPutStatisticsRepository.findByHqlWhere(packBean);
    }


    private MissPartConfirmModel getMissPartConfirm(String serialNumber, String organizeCode) {
        String workOrderNo;
        String workTime;
        MesProduceSnExt produceSnExt = produceSnExtService.getProduceSnExtBySn(organizeCode, serialNumber);
        if (null == produceSnExt) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                    .setErrorDetail("产品条码[%s]无效", serialNumber)
                    .build();
        }

        if (!StringUtils.isEmpty(produceSnExt.getLastWorkOrderNo()) && !produceSnExt.getLastWorkOrderNo().equals(produceSnExt.getWorkOrderNo())) {
            MesProduceSnRepair produceSnRepair = produceSnRepairService.getProduceSnRepairBySn(organizeCode, serialNumber);
            if (null == produceSnRepair) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES_PCN.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                        .setErrorDetail("产品条码[%s]与返工工单[%s]的关联关系不存在", serialNumber, produceSnExt.getLastWorkOrderNo())
                        .build();
            }
            workOrderNo = produceSnRepair.getWorkOrderNo();
            workTime = produceSnRepair.getWorkTime();
        } else {
            workOrderNo = produceSnExt.getWorkOrderNo();
            workTime = produceSnExt.getWorkTime();
        }

        MissPartConfirmModel missPartConfirm = new MissPartConfirmModel();
        missPartConfirm.setOrderNo(workOrderNo);
        missPartConfirm.setPartNo(produceSnExt.getPartNo());
        missPartConfirm.setPartName(produceSnExt.getPartNameRdd());
        missPartConfirm.setWorkTime(workTime);
        return missPartConfirm;
    }

}
