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

import cn.estsh.i3plus.ext.mes.pcn.api.base.INumberRuleExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.base.IPartExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IProductEncodeCfgExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.ISxNumberRuleCheckAttributeService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.ISxNumberRulePackAttributeService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.jx.IJxProdBusiStrategyService;
import cn.estsh.i3plus.ext.mes.pcn.pojo.bean.MesNumberRuleExt;
import cn.estsh.i3plus.ext.mes.pcn.pojo.bean.MesPartExt;
import cn.estsh.i3plus.ext.mes.pcn.pojo.bean.MesProduceSnExt;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.jx.JxProdBusiStrategyParamsBuilder;
import cn.estsh.i3plus.ext.mes.pcn.pojo.repository.MesProduceSnExtRepository;
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.api.iservice.busi.ISyncFuncService;
import cn.estsh.i3plus.mes.pcn.serviceimpl.busi.dispatch.cachedispatch.WorkCellDataCacheDispatch;
import cn.estsh.i3plus.platform.common.convert.ConvertBean;
import cn.estsh.i3plus.pojo.base.bean.BaseResultBean;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.mes.model.GenSerialNoModel;
import cn.estsh.i3plus.pojo.mes.model.StepResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.StringJoiner;

/**
 * @Author: wangjie
 * @CreateDate: 2021/01/18 11:41 上午
 * @Description: 正常工单
 **/
@Slf4j
@Service
public class JxProdBusiStrategyStandardService implements IJxProdBusiStrategyService {

    @Autowired
    private IPartExtService partExtService;

    @Autowired
    private IProductEncodeCfgExtService productEncodeCfgExtService;

    @Autowired
    private INumberRuleExtService numberRuleExtService;

    @Autowired
    private ISxNumberRuleCheckAttributeService numberRuleCheckAttributeService;

    @Autowired
    private ISxNumberRulePackAttributeService numberRulePackAttributeService;

    @Autowired
    private ISyncFuncService syncFuncService;

    @Autowired
    private MesProduceSnExtRepository produceSnExtRepository;

    @Override
    public StepResult checkLineOn(JxProdBusiStrategyParamsBuilder params) {

        StepResult stepResult = ((IJxProdBusiStrategyService) params.getStrategyService()).checkLineOn(params);

        if (!stepResult.isCompleted()) return stepResult;

        if (null == params.getManageCodeDb() && null == params.getProduceSnExtDb()) return stepResult.isCompleted(false).msg(String.format("%s[%s]未匹配到有效的管理编码或产品条码信息,验证失败!", params.getScanName(), params.getScanInfo()));

        if (null != params.getProduceSnExtDb()) return checkLineOn4Ps(params, stepResult);

        return checkLineOn4Mc(params, stepResult);

    }

    private StepResult checkLineOn4Ps(JxProdBusiStrategyParamsBuilder params, StepResult stepResult) {

        if (!StringUtils.isEmpty(params.getProduceSnExtDb().getProcessCode()))
            return stepResult.isCompleted(false).msg(String.format("%s[%s]对应的产品条码信息已经过当前工序,当前条码状态[%s],验证失败!", params.getScanName(), params.getScanInfo(), MesPcnExtEnumUtil.PRODUCE_SN_STATUS.valueOfDescription(params.getProduceSnExtDb().getSnStatus())));

        if (MesPcnExtEnumUtil.SN_OPERATE_TYPE.REPAIR.getValue() == params.getProduceSnExtDb().getOperateType())
            return stepResult.isCompleted(false).msg(String.format("%s[%s]对应的产品条码信息当前业务类型[返修],验证失败!", params.getScanName(), params.getScanInfo()));

        if (null != params.getProduceSnMcRecordDb() && MesPcnExtEnumUtil.SN_OPERATE_TYPE.REPAIR.getValue() == params.getProduceSnMcRecordDb().getOperateType())
            return stepResult.isCompleted(false).msg(String.format("%s[%s]对应的管理编码与工单条码关系信息当前业务类型[返修],验证失败!", params.getScanName(), params.getScanInfo()));

        if (params.getProduceSnExtDb().getLastWorkOrderNo().equals(params.getOrderModel().getOrderNo()) &&
                null != params.getProduceSnMcRecordDb() && !params.getProduceSnMcRecordDb().getWorkOrderNo().equals(params.getOrderModel().getOrderNo()))
            return stepResult.isCompleted(false).msg(String.format("%s[%s]对应的管理编码与工单条码关系信息关联的工单号[%s]与当前生产的工单号[%s]不一致,验证失败!", params.getScanName(), params.getScanInfo(), params.getProduceSnMcRecordDb().getWorkOrderNo(), params.getOrderModel().getOrderNo()));

        if (!params.getProduceSnExtDb().getLastWorkOrderNo().equals(params.getOrderModel().getOrderNo()) &&
                MesPcnExtEnumUtil.PRODUCE_SN_QC_STATUS.QUALIFIED.getValue() == params.getProduceSnExtDb().getQcStatus() && MesPcnExtEnumUtil.PRODUCE_SN_STATUS.REPAIR_PROCESS.getValue() != params.getProduceSnExtDb().getSnStatus())
            return stepResult.isCompleted(false).msg(String.format("%s[%s]对应的产品条码信息关联的工单号[%s]与当前生产的工单号[%s]不一致,验证失败!", params.getScanName(), params.getScanInfo(), params.getProduceSnExtDb().getLastWorkOrderNo(), params.getOrderModel().getOrderNo()));

        if (!params.getProduceSnExtDb().getLastWorkOrderNo().equals(params.getOrderModel().getOrderNo()))
            return stepResult.nextTriggerEvent(MesPcnExtConstWords.TMP_ORDER).msg(String.format("%s[%s]对应的产品条码信息已被标记成[返修品],即将切换到临时工单[%s]!", params.getScanName(), params.getScanInfo(), params.getProduceSnExtDb().getLastWorkOrderNo()));
        else
            return stepResult.msg(String.format("%s[%s]已匹配产品条码信息,验证成功!", params.getScanName(), params.getScanInfo()));

    }

    private StepResult checkLineOn4Mc(JxProdBusiStrategyParamsBuilder params, StepResult stepResult) {

        stepResult.isCompleted(false);

        if (null != params.getProduceSnMcRecordDb() && !params.getProduceSnMcRecordDb().getWorkOrderNo().equals(params.getOrderModel().getOrderNo()))
            return stepResult.msg(String.format("%s[%s]已绑定其他生产工单[%s],验证失败!", params.getScanName(), params.getScanInfo(), params.getProduceSnMcRecordDb().getWorkOrderNo()));

        if (null != params.getProduceSnMcRecordDb())
            return stepResult.msg(String.format("%s[%s]对应的管理编码与工单条码关系信息存在,但未找到对应的产品条码信息,验证失败!", params.getScanName(), params.getScanInfo()));

        Integer count = ((IJxProdBusiStrategyService) params.getStrategyService()).queryOrderBindedQty(params);

        if (count >= params.getOrderModel().getQty())
            return stepResult.msg(String.format("生产工单[%s]计划数量[%s]管理编码绑定数量已达标,请切换生产工单!", params.getOrderModel().getOrderNo(), params.getOrderModel().getQty()));

        return stepResult.isCompleted(true).msg(String.format("%s[%s]验证成功!", params.getScanName(), params.getScanInfo()));

    }

    @Override
    public StepResult execLineOnBindMc(JxProdBusiStrategyParamsBuilder params) {

        StepResult stepResult = StepResult.getNonComplete();

        MesPartExt partDb = partExtService.getPartExt(params.getOrganizeCode(), params.getOrderModel().getPartNo());
        if (null == partDb) return stepResult.msg(String.format("工单号[%s]关联的物料编码[%s]信息不存在!", params.getOrderModel().getOrderNo(), params.getOrderModel().getPartNo()));

        String ruleCode;
        try {
            ruleCode = productEncodeCfgExtService.getRuleCodeByMatchType(params.getOrganizeCode(), MesPcnExtEnumUtil.ENCODE_CODE_TYPE.SERIAL_SN.getValue(), partDb, params.getWorkCenterCode());
        } catch (Exception e) {
            return stepResult.msg(e.getMessage());
        }

        if (StringUtils.isEmpty(ruleCode)) return stepResult.msg(String.format("工单号[%s]关联的物料编码[%s]未配置有效的过程编码匹配规则!", params.getOrderModel().getOrderNo(), params.getOrderModel().getPartNo()));

        Map<String, Object> map = new HashMap<>();
        map.put(MesPcnExtConstWords.ORGANIZE_CODE, params.getOrganizeCode());
        map.put(MesPcnExtConstWords.RULE_CODE, ruleCode);
        map.put(MesPcnExtConstWords.PART_EXT, partDb);
        map.put(MesPcnExtConstWords.WORK_ORDER_NO, params.getOrderModel().getOrderNo());
        map.put(MesPcnExtConstWords.WORK_CENTER_CODE, params.getWorkCenterCode());
        GenSerialNoModel genSerialNoModel = numberRulePackAttributeService.doPackGenSerialNoModel(map);

        BaseResultBean<String> baseResultBean = syncFuncService.syncSerialNo(genSerialNoModel, params.getUserInfo(), params.getOrganizeCode(), 1);
        if (null == baseResultBean || (!baseResultBean.isSuccess() || CollectionUtils.isEmpty(baseResultBean.getResultList())))
            return stepResult.msg(String.format("工单号[%s]关联的物料编码[%s]配置的过程编码匹配规则编码[%s]生成过程条码失败:%s!", params.getOrderModel().getOrderNo(), params.getOrderModel().getPartNo(), ruleCode, null != baseResultBean ? baseResultBean.getErrorMsg() : null));

        ((IJxProdBusiStrategyService) params.getStrategyService()).insertProduceSnMcRecord(params.serialNumber(baseResultBean.getResultList().get(0)));

        insertProduceSnExt(params);

        ((IJxProdBusiStrategyService) params.getStrategyService()).insertProduceSnTravel(params);

        return stepResult.isCompleted(true).data(params.getProduceSnMcRecordDb());

    }

    private void insertProduceSnExt(JxProdBusiStrategyParamsBuilder params) {
        MesProduceSnExt produceSnExt = new MesProduceSnExt();
        produceSnExt.setSerialNumber(params.getSerialNumber());
        produceSnExt.setWorkOrderNo(params.getOrderModel().getOrderNo());
        produceSnExt.setLastWorkOrderNo(params.getOrderModel().getOrderNo());
        produceSnExt.setPartNo(params.getOrderModel().getPartNo());
        produceSnExt.setPartNameRdd(params.getOrderModel().getPartNameRdd());
        produceSnExt.setPrintStatus(MesPcnExtEnumUtil.PRODUCE_SN_PRINT_STATUS.UNPRINT.getValue());
        produceSnExt.setPrintCount(0);
        produceSnExt.setSnStatus(MesPcnExtEnumUtil.PRODUCE_SN_STATUS.CREATE.getValue());
        produceSnExt.setQcStatus(MesPcnExtEnumUtil.PRODUCE_SN_QC_STATUS.QUALIFIED.getValue());
        produceSnExt.setSnType(MesPcnExtEnumUtil.PRODUCE_SN_TYPE.STANDARD_SN.getValue());
        produceSnExt.setQty(1d);
        produceSnExt.setWorkCenterCode(params.getWorkCenterCode());
        produceSnExt.setTrayNo(params.getManageCode());
        produceSnExt.setOperateType(MesPcnExtEnumUtil.SN_OPERATE_TYPE.QUALIFIED.getValue());
        produceSnExt.setIfCompensate(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue());
        produceSnExt.setOrganizeCode(params.getOrganizeCode());
        ConvertBean.serviceModelInitialize(produceSnExt, params.getUserInfo());
        produceSnExt.setInWorkCenterTime(produceSnExt.getCreateDatetime());
        produceSnExt.setSystemSyncStatus(MesPcnExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        new ConvertBeanExt(produceSnExt).convertBean(produceSnExt);
        params.produceSnExtDb(produceSnExtRepository.insert(produceSnExt));
    }

    @Override
    public StepResult checkThirdPartyPs(JxProdBusiStrategyParamsBuilder params) {

        StepResult stepResult = StepResult.getNonComplete();

        if (!checkProduceSnIsScanOtherCell(params, stepResult)) return stepResult;

        MesPartExt partDb = partExtService.getPartExt(params.getOrganizeCode(), params.getOrderModel().getPartNo());

        if (null == partDb) return stepResult.msg(String.format("生产工单[%s]关联的物料编码[%s]对应的物料信息不存在!", params.getOrderModel().getOrderNo(), params.getOrderModel().getPartNo()));

        if (StringUtils.isEmpty(partDb.getProductMatchType()))
            return stepResult.msg(String.format("生产工单[%s]关联的物料编码[%s]对应的物料信息未配置产品编码匹配类型!", params.getOrderModel().getOrderNo(), params.getOrderModel().getPartNo()));

        String ruleCode;
        try {
            ruleCode = productEncodeCfgExtService.getRuleCodeByMatchType(
                    params.getOrganizeCode(), MesPcnExtEnumUtil.ENCODE_CODE_TYPE.STANDARD_SERIAL_SN.getValue(), partDb, params.getOrderModel().getWorkCenterCode());
        } catch (Exception e) {
            return stepResult.msg(String.format("生产工单[%s]关联的物料编码[%s]:[%s]!", params.getOrderModel().getOrderNo(), params.getOrderModel().getPartNo(), e.getMessage()));
        }

        MesNumberRuleExt numberRuleDb = numberRuleExtService.getNumberRuleExtByRuleCode(params.getOrganizeCode(), ruleCode);
        if (null == numberRuleDb || StringUtils.isEmpty(numberRuleDb.getNumberRule()) ||
                StringUtils.isEmpty(numberRuleDb.getRuleLengthSpilt()) || StringUtils.isEmpty(numberRuleDb.getMethodName()))
            return stepResult.msg(String.format("生产工单[%s]关联的物料编码[%s]配置的编码规则代码[%s]无效!", params.getOrderModel().getOrderNo(), params.getOrderModel().getPartNo(), ruleCode));

        Map<String, Object> map = new HashMap<>();
        map.put(MesPcnExtConstWords.SERIAL_NUMBER, params.getScanInfo());
        map.put(MesPcnExtConstWords.NUMBER_RULE_EXT, numberRuleDb);
        map.put(MesPcnExtConstWords.PART_EXT, partDb);
        if (!(Boolean) numberRuleCheckAttributeService.doCheckNumberRule(map).get(MesPcnExtConstWords.RESULT))
            return stepResult.msg(String.format("产品条码[%s]与生产工单[%s]关联的物料编码[%s]配置的编码规则不匹配,操作失败!", params.getScanInfo(), params.getOrderModel().getOrderNo(), params.getOrderModel().getPartNo()));

        ((IJxProdBusiStrategyService) params.getStrategyService()).queryProduceSnInfo(params.productSn(params.getScanInfo()));

        if (null != params.getProduceSnExtDb())
            return stepResult.msg(String.format("产品条码[%s]已绑定过生产工单[%s],操作失败!", params.getScanInfo(), params.getProduceSnExtDb().getWorkOrderNo()));

        return stepResult.isCompleted(true);

    }

    private synchronized Boolean checkProduceSnIsScanOtherCell(JxProdBusiStrategyParamsBuilder params, StepResult stepResult) {

        if (StringUtils.isEmpty(params.getLockContent())) return true;

        String key = new StringJoiner(MesPcnExtConstWords.COLON).add(params.getOrganizeCode()).add(MesPcnExtConstWords.JX_THIRD_PARTY_SN_LOCK).add(params.getLockContent()).toString();
        String curCell = new StringJoiner(MesPcnExtConstWords.COLON).add(params.getOrganizeCode()).add(params.getWorkCenterCode()).add(params.getWorkCellCode()).toString();

        WorkCellDataCacheDispatch dispatch = new WorkCellDataCacheDispatch.builder().key(key).build().get();

        if (!StringUtils.isEmpty(dispatch.getValue()) && !dispatch.getValue().equals(curCell))
            return stepResult.msg(String.format("产品条码[%s]已在生产线[%s]工位[%s]被扫描,请扫描其他条码或5秒后重试当前条码,操作失败!",
                    params.getLockContent(), dispatch.getValue().split(MesPcnExtConstWords.COLON)[1], dispatch.getValue().split(MesPcnExtConstWords.COLON)[2])).isCompleted();

        new WorkCellDataCacheDispatch.builder().key(key).value(curCell).timeSecond(5).build().get();

        return true;

    }

    @Override
    public StepResult execLineOff(JxProdBusiStrategyParamsBuilder params) { return ((IJxProdBusiStrategyService) params.getStrategyService()).execLineOff(params); }

}