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

import cn.estsh.i3plus.ext.mes.pcn.api.base.IMesProdOrgExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.base.IMesTemplateService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesFengRenBatchReportService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesProductVersionService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesWorkOrderService;
import cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.print.IPrintTemplateStrategyService;
import cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.step.method.IMesPackageNoGenerateStepService;
import cn.estsh.i3plus.ext.mes.pcn.apiservice.util.MesPcnException;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesPackageDataContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.MesPackageRuleContext;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.MesProduceSnPrintModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.model.MesWorkOrderExtModel;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords;
import cn.estsh.i3plus.mes.pcn.api.iservice.base.IPartService;
import cn.estsh.i3plus.platform.common.convert.ConvertBean;
import cn.estsh.i3plus.platform.common.tool.MathOperation;
import cn.estsh.i3plus.platform.common.tool.TimeTool;
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.base.util.StringUtil;
import cn.estsh.i3plus.pojo.mes.bean.*;
import cn.estsh.i3plus.pojo.mes.model.StationRequestBean;
import cn.estsh.i3plus.pojo.mes.model.StepResult;
import cn.estsh.i3plus.pojo.mes.repository.MesPartProdGroupRepository;
import cn.estsh.i3plus.pojo.mes.repository.MesProductOffLineRepository;
import cn.estsh.i3plus.pojo.mes.repository.MesWorkOrderLogRepository;
import cn.estsh.i3plus.pojo.mes.repository.MesWorkOrderRepository;
import cn.estsh.i3plus.pojo.mes.util.MesExtEnumUtil;
import cn.estsh.impp.framework.boot.util.SpringContextsUtil;
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 java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Slf4j
@Service
public class MesFengRenBatchReportService implements IMesFengRenBatchReportService {

    @Autowired
    private IMesPackageNoGenerateStepService packageNoGenerateStepService;

    @Autowired
    private IMesProdOrgExtService prodOrgExtService;

    @Autowired
    private IPartService partService;

    @Autowired
    private IMesProductVersionService productVersionService;

    @Autowired
    private IMesWorkOrderService workOrderService;

    @Autowired
    private IMesTemplateService templateService;

    @Autowired
    private MesWorkOrderRepository workOrderRepository;

    @Autowired
    private MesPartProdGroupRepository partProdGroupRepository;

    @Autowired
    private MesWorkOrderLogRepository workOrderLogRepository;

    @Autowired
    private MesProductOffLineRepository productOffLineRepository;

    @Override
    public MesPackageRuleContext queryPackSpecQtyFengRenBatchReport(String organizeCode, String partNo) {
        StepResult stepResult = StepResult.getSuccessComplete();
        StationRequestBean reqBean = new StationRequestBean();
        reqBean.setOrganizeCode(organizeCode);
        return queryPackSpecQtyFengRenBatchReport(reqBean, stepResult, partNo);
    }

    private MesPackageRuleContext queryPackSpecQtyFengRenBatchReport(StationRequestBean reqBean, StepResult stepResult, String partNo) {

        MesPackageRuleContext packageRuleContext = packageNoGenerateStepService.getPackageRuleContext(reqBean, stepResult, partNo, true);
        if (null == packageRuleContext) MesPcnException.throwBusiException(!StringUtils.isEmpty(stepResult.getMsg()) ? stepResult.getMsg() : String.format("零件[%s]未维护有效的成品包装主数据!", partNo));
        return packageRuleContext;
    }

    @Override
    public MesProduceSnPrintModel doFengRenBatchReport(MesWorkOrderExtModel model) {

        //验证工单有效性
        MesWorkOrder workOrderDb = workOrderRepository.getByProperty(
                new String[]{MesPcnExtConstWords.ID, MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.IS_VALID},
                new Object[]{model.getId(), model.getOrganizeCode(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.IS_VAILD.VAILD.getValue()});
        if (null == workOrderDb) MesPcnException.throwBusiException("汇报失败:生产工单[%s]信息不存在!", model.getWorkOrderNo());

        if (!StringUtils.isEmpty(workOrderDb.getOrderFlag()) && MesExtEnumUtil.ORDER_TYPE_IDENTIFICATION.P.getValue().equals(workOrderDb.getOrderFlag()))
            MesPcnException.throwBusiException("汇报失败:生产工单[%s]为试制工单!", model.getWorkOrderNo());

        if (!MesExtEnumUtil.ORDER_STATUS.checkNosortAllowStatus(workOrderDb.getWorkOrderStatus()))
            MesPcnException.throwBusiException("汇报失败:生产工单[%s]信息当前状态[%s]!", MesExtEnumUtil.ORDER_STATUS.valueOfDescription(workOrderDb.getWorkOrderStatus()));

        //验证超工单
        Double reportedQty = MathOperation.add(new Double(model.getNum()), workOrderDb.getReportedQty());
        Integer workOrderStatus = MesExtEnumUtil.ORDER_STATUS.COMPLETE.getValue();
        if (MathOperation.compareTo(reportedQty, workOrderDb.getQty()) > 0) {
            MesWorkCenter workCenter = prodOrgExtService.getWorkCenterDb(model.getOrganizeCode(), workOrderDb.getWorkCenterCode());

            if (StringUtils.isEmpty(workCenter.getIsCheckOrderQty()) || workCenter.getIsCheckOrderQty().compareTo(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) != 0)
                MesPcnException.throwMesBusiException("汇报失败:工单号[%s]计划数量[%s]已报工数量[%s],当前不允许超工单!", workOrderDb.getWorkOrderNo(), workOrderDb.getQty(), workOrderDb.getReportedQty());

            Double rate = MathOperation.div((MathOperation.sub(reportedQty, workOrderDb.getQty())), workOrderDb.getQty());
            if (MathOperation.compareTo(rate, MathOperation.div(workCenter.getOrderRate(), new Double(MesPcnExtConstWords.ONE_HUNDRED))) > 0)
                MesPcnException.throwMesBusiException("汇报失败:请检查工单数量,工单号[%s]计划数量[%s]已报工数量[%s]超工单比例[%s]!", workOrderDb.getWorkOrderNo(), workOrderDb.getQty(), workOrderDb.getReportedQty(), workCenter.getOrderRate());

        }

        //查询物料信息
        MesPart mesPart = partService.getPartByNo(workOrderDb.getOrganizeCode(), workOrderDb.getPartNo());
        if (null == mesPart) MesPcnException.throwBusiException(
                "汇报失败:生产工单[%s]关联的零件编码[%s]信息不存在!", workOrderDb.getWorkOrderNo(), workOrderDb.getPartNo());

        //获取生产版本
        MesProductVersion mesProductVersion = productVersionService.getMesProductVersion(workOrderDb.getOrganizeCode(), workOrderDb.getPartNo(), workOrderDb.getProductVersion());
        if (null == mesProductVersion) MesPcnException.throwBusiException(
                "汇报失败:生产工单[%s]零件编码[%s]生产版本[%s]未维护生产版本信息!", workOrderDb.getWorkOrderNo(), workOrderDb.getPartNo(), workOrderDb.getProductVersion());

        String bomVersion =  mesProductVersion.getAlternativePartList();

        // partProdGroupCode 不为空，查询的数据不为空，查询数据中的获取bom方式不为空且枚举是 基于默认BOM ，才bomversion = null 否则都是通过生产版本找bom
        if (!StringUtil.isEmpty(workOrderDb.getPartProdGroupCode())) {
            DdlPackBean partProdBean = DdlPackBean.getDdlPackBean(workOrderDb.getOrganizeCode());
            DdlPreparedPack.getStringEqualPack(workOrderDb.getPartProdGroupCode(), MesPcnExtConstWords.PART_PROD_GROUP_CODE, partProdBean);
            List<MesPartProdGroup> mesPartProdGroupList = partProdGroupRepository.findByHqlTopWhere(partProdBean, 1);

            // 没有零件生产组用默认找生产版本、有的话找获取bom方式枚举，枚举是基于默认BOM 则直接找
            MesPartProdGroup mesPartProdGroup = !CollectionUtils.isEmpty(mesPartProdGroupList) ? mesPartProdGroupList.get(0) : null;
            if (null != mesPartProdGroup && !StringUtils.isEmpty(mesPartProdGroup.getEnableBomVersion()) &&
                    mesPartProdGroup.getEnableBomVersion() == MesExtEnumUtil.ENABLE_BOM_VERSION.ENABLE_BOM_VERSION_2.getValue()) {
                bomVersion = MesPcnExtConstWords.EMPTY;
            }
        }

        log.info("工厂{}缝纫批量汇报 --- PROCESS_INFO --- MesWorkOrderDB:{} --- MesProductVersion:{} --- bomVersion:{} --- {}", model.getOrganizeCode(), JSONObject.toJSONString(workOrderDb), JSONObject.toJSONString(mesProductVersion), bomVersion, Thread.currentThread().getName());

        //物料+生产版本获取bom信息
        List<MesBom> mesBoms = workOrderService.findBomList(mesPart.getOrganizeCode(), mesPart, bomVersion);

        //获取标包, 编码规则, 模版代码
        StepResult stepResult = StepResult.getSuccessComplete();
        StationRequestBean reqBean = new StationRequestBean();
        reqBean.setOrganizeCode(model.getOrganizeCode());
        reqBean.setWorkCenterCode(workOrderDb.getWorkCenterCode());
        reqBean.setUserInfo(model.getModifyUser());
        reqBean.getDataMap().put(MesPcnExtConstWords.MESSAGE, "缝纫批量汇报");
        MesPackageDataContext packageDataContext = (MesPackageDataContext) queryPackSpecQtyFengRenBatchReport(reqBean, stepResult, model.getPartNo());

        //计数
        Double unCompleteQty = MathOperation.sub(workOrderDb.getQty(), reportedQty);
        if (MathOperation.compareTo(unCompleteQty, new Double(0)) < 0) unCompleteQty = new Double(0);
        if (MathOperation.compareTo(reportedQty, workOrderDb.getQty()) < 0) workOrderStatus = MesExtEnumUtil.ORDER_STATUS.PROCESS.getValue();

        log.info("工厂{}缝纫批量汇报 --- PROCESS_INFO --- MesBomSize:{} --- MesPackageDataContext:{} --- workOrderStatus:{} --- reportedQty:{} --- {}", model.getOrganizeCode(), mesBoms.size(), JSONObject.toJSONString(packageDataContext), workOrderStatus, reportedQty, Thread.currentThread().getName());

        //查询模版信息
        MesLabelTemplate labelTemplate = templateService.getLabelTemplate(packageDataContext.getPackageTemplate(), reqBean.getOrganizeCode());
        IPrintTemplateStrategyService strategyService = (null != labelTemplate && !StringUtils.isEmpty(labelTemplate.getMethodCode())) ? (IPrintTemplateStrategyService) SpringContextsUtil.getBean(labelTemplate.getMethodCode()) : null;
        if (null == strategyService) MesPcnException.throwBusiException(
                "汇报失败:生产工单[%s]关联的零件编码[%s]未配置有效的包装条码模版[%s]信息!", workOrderDb.getWorkOrderNo(), workOrderDb.getPartNo());

        //生成箱条码集合
        packageDataContext.setGenerateType(MesExtEnumUtil.PACKING_RULE_GENERATE_TYPE.PACKAGE.getValue());
        packageDataContext.setPartPackWorkOrderNo(workOrderDb.getWorkOrderNo());
        packageDataContext.setQty(new Double(model.getNum()));
        stepResult.setDataCollection(new ArrayList());
        packageNoGenerateStepService.doHandlePackagePrint(reqBean, stepResult, packageDataContext, null, packageNoGenerateStepService.generateVirtualPs(packageDataContext.getQty()), true);
        //进行打印
        List<MesPackage> packageList = (List<MesPackage>) stepResult.getDataCollection();
        MesProduceSnPrintModel printModel = packageNoGenerateStepService.doPrintPackageNo(reqBean, null, stepResult, packageDataContext, labelTemplate, strategyService, packageList, true);

        //更新工单
        updateMesWorkOrder(workOrderDb, model, workOrderStatus, reportedQty, unCompleteQty);

        //遍历写汇报
        List<MesProductOffLine> mesProductOffLineList = new ArrayList<>();
        for (MesPackage mesPackage : packageList) {
            if (null == mesPackage) continue;
            String nowTime = StringUtil.isEmpty(model.getDescription()) ? TimeTool.getNowTime(true) : model.getDescription();
            for (MesBom mesBom : mesBoms) {
                mesProductOffLineList.add(creatMesProductOffLine(model.getModifyUser(), workOrderDb, mesProductVersion, mesPackage.getPackageOneCode(), mesPackage.getPackageNo(), mesPackage.getQty(), mesBom, nowTime, mesBoms.size()));
            }
        }
        productOffLineRepository.saveAll(mesProductOffLineList);
        log.info("工厂{}缝纫批量汇报 --- PROCESS_INFO --- MesProductOffLine:{} --- {}", model.getOrganizeCode(), JSONObject.toJSONString(mesProductOffLineList), Thread.currentThread().getName());

        log.info("工厂{}缝纫批量汇报 --- PROCESS_INFO --- MesPackageList:{} --- {}", model.getOrganizeCode(), JSONObject.toJSONString(packageList), Thread.currentThread().getName());

        return printModel;
    }

    private void updateMesWorkOrder(MesWorkOrder mesWorkOrder, MesWorkOrderExtModel model, Integer workOrderStatus, Double reportedQty, Double unCompleteQty) {
        ConvertBean.serviceModelUpdate(mesWorkOrder, model.getModifyUser());
        String now = (new SimpleDateFormat(MesPcnExtConstWords.DATE_FORMAT_SSS)).format(new Date());
        workOrderRepository.updateByPropertiesNoSync(
                new String[]{MesPcnExtConstWords.ID, MesPcnExtConstWords.ORGANIZE_CODE},
                new Object[]{mesWorkOrder.getId(), mesWorkOrder.getOrganizeCode()},
                new String[]{MesPcnExtConstWords.WORK_ORDER_STATUS, MesPcnExtConstWords.REPORTED_QTY, MesPcnExtConstWords.COMPLETE_QTY, MesPcnExtConstWords.UN_COMPLETE_QTY,
                        MesPcnExtConstWords.DESCRIPTION, MesPcnExtConstWords.REMARK, MesPcnExtConstWords.MODIFY_DATE_TIME, MesPcnExtConstWords.MODIFY_USER, MesPcnExtConstWords.SYSTEM_SYNC_STATUS, MesPcnExtConstWords.SYSTEM_SYNC_DATE_TIME},
                new Object[]{workOrderStatus, reportedQty, reportedQty, unCompleteQty,
                        model.getDescription(), model.getDescription(), now, model.getModifyUser(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), MesPcnExtConstWords.EMPTY});

        MesWorkOrderLog workOrderLog = new MesWorkOrderLog();
        BeanUtils.copyProperties(mesWorkOrder, workOrderLog, MesPcnExtConstWords.ID,
                MesPcnExtConstWords.CREATE_USER, MesPcnExtConstWords.MODIFY_USER, MesPcnExtConstWords.SYSTEM_SYNC_STATUS, MesPcnExtConstWords.SYSTEM_SYNC_DATE_TIME);
        workOrderLog.setType(MesExtEnumUtil.WORK_ORDER_LOG_TYPE.REPORT.getValue());
        workOrderLog.setModifyQty(new Double(model.getNum()));
        workOrderLog.setDescription(model.getDescription());
        workOrderLog.setRemark(model.getDescription());
        workOrderLog.setWorkOrderStatus(workOrderStatus);
        workOrderLog.setReportedQty(reportedQty);
        workOrderLog.setCompleteQty(reportedQty);
        workOrderLog.setUnCompleteQty(unCompleteQty);
        workOrderLog.setCreateDatetime(model.getModifyUser());
        workOrderLog.setModifyUser(model.getModifyUser());
        workOrderLog.setCreateDatetime(now);
        workOrderLog.setModifyDatetime(now);
        workOrderLogRepository.insert(workOrderLog);
    }

    private MesProductOffLine creatMesProductOffLine(String userName, MesWorkOrder workOrderDb, MesProductVersion mesProductVersion,
                                                     String reportSn, String serialNumber, Double num, MesBom mesBom, String nowTime, Integer bomTotalSize) {
        MesProductOffLine newMesProductOffLine = new MesProductOffLine();
        newMesProductOffLine.setReportPartNo(workOrderDb.getPartNo());
        newMesProductOffLine.setReportPartNameRdd(workOrderDb.getPartName());
        newMesProductOffLine.setReportSn(reportSn);
        newMesProductOffLine.setSerialNumber(serialNumber);
        newMesProductOffLine.setItemPartNo(mesBom.getItemPartNo());
        newMesProductOffLine.setItemPartName(mesBom.getItemPartName());
        newMesProductOffLine.setItemQty(MathOperation.mul(num, mesBom.getItemQty()));
        newMesProductOffLine.setAlort(mesProductVersion.getReceiveInventoryPoint());
        newMesProductOffLine.setStgeLoc(mesProductVersion.getShipInventoryPoint());
        newMesProductOffLine.setQty(num);
        newMesProductOffLine.setBomVersion(workOrderDb.getProductVersion());
        newMesProductOffLine.setUnit(mesBom.getUnit());
        newMesProductOffLine.setItemUnit(mesBom.getItemUnit());
        newMesProductOffLine.setWorkOrderNo(workOrderDb.getWorkOrderNo());
        newMesProductOffLine.setWorkOrderType(workOrderDb.getWorkOrderType());
        newMesProductOffLine.setWorkCenterCode(mesProductVersion.getWorkCenterCode());
        newMesProductOffLine.setWorkCellCode(workOrderDb.getWorkCellCode());
        newMesProductOffLine.setReportType(MesExtEnumUtil.MES_ALL_REPORT_TYPE.REPORT.getValue());
        newMesProductOffLine.setSapWorkCenter(mesProductVersion.getWorkCenterCode());
        newMesProductOffLine.setOrganizeCode(workOrderDb.getOrganizeCode());
        newMesProductOffLine.setDescription(nowTime);
        newMesProductOffLine.setBomTotalSize(bomTotalSize);
        newMesProductOffLine.setBomCode(mesBom.getBomCode());
        ConvertBean.serviceModelInitialize(newMesProductOffLine, userName);
        return newMesProductOffLine;
    }

}
