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

import cn.estsh.i3plus.ext.mes.pcn.api.base.IMesProdShiftRecordService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesProductionCustomContextStepService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesProductionDispatchContextStepService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesProductionProcessContextStepService;
import cn.estsh.i3plus.ext.mes.pcn.api.busi.IMesProductionRecordService;
import cn.estsh.i3plus.ext.mes.pcn.pojo.context.*;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords;
import cn.estsh.i3plus.mes.pcn.serviceimpl.fsm.BaseStepService;
import cn.estsh.i3plus.platform.common.convert.ConvertBean;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.enumutil.MesPcnEnumUtil;
import cn.estsh.i3plus.pojo.mes.bean.MesProductionRecord;
import cn.estsh.i3plus.pojo.mes.bean.MesWorkCell;
import cn.estsh.i3plus.pojo.mes.bean.MesWorkCenter;
import cn.estsh.i3plus.pojo.mes.model.StationRequestBean;
import cn.estsh.i3plus.pojo.mes.model.StationResultBean;
import cn.estsh.i3plus.pojo.mes.model.StepResult;
import cn.estsh.i3plus.pojo.mes.repository.MesProductionRecordRepository;
import cn.estsh.i3plus.pojo.mes.util.MesExtEnumUtil;
import com.google.common.base.Objects;
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.*;
import java.util.stream.Collectors;

/**
 * @Description : 生成加工记录工步
 * @Author : wangjie
 **/
@Slf4j
@Service("mesProductionRecordGenerateStepService")
public class MesProductionRecordGenerateStepService extends BaseStepService {

    @Autowired
    private IMesProductionProcessContextStepService productionProcessContextStepService;

    @Autowired
    private IMesProductionDispatchContextStepService productionDispatchContextStepService;

    @Autowired
    private MesProductionRecordRepository productionRecordRepository;

    @Autowired
    private MesProductionRecordRepository mesProductionRecordRepository;

    @Autowired
    private IMesProductionCustomContextStepService productionCustomContextStepService;

    @Autowired
    private IMesProductionRecordService productionRecordService;

    @Autowired
    private IMesProdShiftRecordService prodShiftRecordService;

    //当前非排序线, 排序线有差异
    @Override
    public StepResult execute(StationRequestBean reqBean) {

        StationResultBean resultBean = new StationResultBean();

        StepResult stepResult = StepResult.getSuccessComplete();

        //获取上下文信息
        MesProductionProcessContext productionProcessContext = productionProcessContextStepService.dispatchCurCellEquipment(reqBean);

        //配置错误 抛出异常
        if (!productionProcessContext.getSuccess()) stepExpSendMsgAndThrowEx(reqBean, resultBean.writeDbLog(), productionProcessContext.getMessage());

        //存储生产过程上下文对象
        productionProcessContextStepService.dispatchProductionProcessContext(reqBean, productionProcessContext);

        //获取上下文产品加工规则数据信息集合
        List<MesProdRuleContext> prodRuleContextList = productionDispatchContextStepService.getProdRuleDataContext(reqBean);

        if (CollectionUtils.isEmpty(prodRuleContextList)) stepExpSendMsgAndThrowEx(reqBean, resultBean.writeDbLog(), "当前不存在非排序加工规则数据,请重置工序!");

        //获取上下文产出条码数据信息集合
        List<MesProductionPsOutContext> productionPsOutContextList = productionDispatchContextStepService.getProductionPsOutContext(reqBean);

        if (CollectionUtils.isEmpty(productionPsOutContextList)) stepExpSendMsgAndThrowEx(reqBean, resultBean.writeDbLog(), "当前不存在产出零件条码信息,请重置工序解决!");

        //从上下文中取出工位当前要使用的设备
        MesCellEquipContext cellEquipContext = productionProcessContext.getCurCellEquip();

        //获取上下文进料零件条码信息集合
        List<MesProductionPsInContext> productionPsInContextList = productionDispatchContextStepService.getProductionPsInContext(reqBean);
        Map<Integer, MesProductionPsInContext> psiMap = CollectionUtils.isEmpty(productionPsInContextList) ? null : productionPsInContextList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getForeignKey()))).collect(Collectors.toMap(MesProductionPsInContext::getForeignKey, o -> o));

        Map<Integer, MesProdRuleContext> prMap = CollectionUtils.isEmpty(prodRuleContextList) ? null : prodRuleContextList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getForeignKey()))).collect(Collectors.toMap(MesProdRuleContext::getForeignKey, o -> o));

        MesWorkCenter workCenter = productionProcessContext.getWorkCenter();
        MesWorkCell workCell = productionProcessContext.getWorkCell();

        //获取上下文产出零件信息【当前非排序才需要查询, 用于验证P单则不汇报】
        List<MesProductionPartContext> productionPartContextList = workCenter.getCenterType().compareTo(MesExtEnumUtil.WORK_CENTER_TYPE.NOSORT.getValue()) == 0 ? productionDispatchContextStepService.getProductionPartContext(reqBean) : null;
        Map<Integer, MesProductionPartContext> ppcMap = CollectionUtils.isEmpty(productionPartContextList) ? null : productionPartContextList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getForeignKey()))).collect(Collectors.toMap(MesProductionPartContext::getForeignKey, o -> o));

        //获取上下文(头道)模具号
        String mouldNo = getMouldNo(reqBean, workCenter, prodRuleContextList);

        //获取上下文工位扫描监控信息
        MesScanMonitorContext scanMonitorContext = productionProcessContextStepService.dispatchScanMonitorContext(reqBean, true);

        //生成加工记录
        productionPsOutContextList.stream().filter(o -> null != o).forEach(o ->
                saveProductionRecordData(reqBean, workCenter, scanMonitorContext, mouldNo, prodRuleContextList, productionProcessContext, o, prMap, cellEquipContext,
                        CollectionUtils.isEmpty(psiMap) ? null : psiMap.get(o.getForeignKey()), CollectionUtils.isEmpty(ppcMap) ? null : ppcMap.get(o.getForeignKey()))
        );

        //保存上下文产品加工规则信息集合
        productionDispatchContextStepService.dispatchProdRuleDataContext(reqBean, prodRuleContextList);

        if (Objects.equal(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue(), workCell.getIsCountFinish())) {
            // 保存班次加工数量上下文
            MesProdShiftContext mesProdShiftKvBean = prodShiftRecordService.getMesProdShiftKvBean(reqBean.getOrganizeCode(), reqBean.getWorkCenterCode());
            Integer amount = productionCustomContextStepService.dispatchProductionStatisticsContext(reqBean, productionPsOutContextList.size(), mesProdShiftKvBean);
            this.sendMessage(reqBean, new StationResultBean().writeDbLog(MesPcnEnumUtil.WORK_CELL_SCAN_MONITOR_LOG_TYPE.PROCESS.getValue()), String.format("生产线[%s]工位[%s]当前累加数[%s]已累计加工数[%s]", reqBean.getWorkCenterCode(), reqBean.getWorkCellCode(), productionPsOutContextList.size(), amount), MesPcnEnumUtil.STATION_BUSI_TYPE.RUNNING_INFO, MesPcnEnumUtil.STATION_DATA_TYPE.TEXT);
        }

        return stepSuccessCompleteAndSendMsgReturn(reqBean, resultBean.writeDbLog(MesPcnEnumUtil.WORK_CELL_SCAN_MONITOR_LOG_TYPE.PROCESS.getValue()), stepResult, "生成加工记录成功!");

    }

    private void saveProductionRecordData(StationRequestBean reqBean, MesWorkCenter workCenter, MesScanMonitorContext scanMonitorContext, String mouldNo,
                                          List<MesProdRuleContext> prodRuleContextList, MesProductionProcessContext productionProcessContext, MesProductionPsOutContext productionPsOutContext,
                                          Map<Integer, MesProdRuleContext> prMap, MesCellEquipContext cellEquipContext, MesProductionPsInContext productionPsInContext, MesProductionPartContext productionPartContext) {

        MesProdRuleContext prodRuleContext = CollectionUtils.isEmpty(prMap) ? null : prMap.get(productionPsOutContext.getForeignKey());

        MesProductionRecord productionRecord = new MesProductionRecord();
        BeanUtils.copyProperties(productionPsOutContext, productionRecord, MesPcnExtConstWords.BASE_BEAN_FIELDS);

        productionRecord.setMouldNo(mouldNo);
        productionRecord.setEquipmentCode(cellEquipContext.getEquipmentCode());
        productionRecord.setEquipmentName(cellEquipContext.getEquipmentName());

        if (workCenter.getCenterType().compareTo(MesExtEnumUtil.WORK_CENTER_TYPE.NOSORT.getValue()) == 0) {
            //非排序
            productionRecord.setReportType((null != prodRuleContext && !StringUtils.isEmpty(prodRuleContext.getReportType()) && prodRuleContext.getReportType().compareTo(MesPcnExtConstWords.ZERO) != 0) ? prodRuleContext.getReportType() : MesExtEnumUtil.NOSORT_REPORT_TYPE.NO_REPORT.getValue());
            if (productionRecord.getReportType().compareTo(MesExtEnumUtil.NOSORT_REPORT_TYPE.NO_REPORT.getValue()) != 0) productionRecord.setReportPartNo(productionPsOutContext.getPartNo());
            productionRecord.setReportStatus(productionRecord.getReportType().compareTo(MesExtEnumUtil.NOSORT_REPORT_TYPE.NO_REPORT.getValue()) != 0 ? MesExtEnumUtil.REPORT_STATUS.REPORT_STATUS_10.getValue() : MesExtEnumUtil.REPORT_STATUS.REPORT_STATUS_30.getValue());
        } else {
            //排序
            List<MesProductionAssemblySortContext> productionAssemblySortContextList = prodRuleContext.getSortAssemblyDataContext();
            Optional<MesProductionAssemblySortContext> optional = CollectionUtils.isEmpty(productionAssemblySortContextList) ? null :
                    productionAssemblySortContextList.stream().filter(o -> (null != o
                            && !StringUtils.isEmpty(o.getWorkCellCode()) && !StringUtils.isEmpty(o.getReportType())
                            && o.getWorkCellCode().equals(reqBean.getWorkCellCode())
                            && o.getReportType().compareTo(MesExtEnumUtil.MES_REPORT_TYPE.NO_REPORT.getValue()) != 0
                            && o.getReportType().compareTo(MesPcnExtConstWords.ZERO) != 0)).findFirst();
            if (null == optional || !optional.isPresent()) {
                productionRecord.setReportType(MesExtEnumUtil.MES_REPORT_TYPE.NO_REPORT.getValue());
                productionRecord.setReportStatus(MesExtEnumUtil.REPORT_STATUS.REPORT_STATUS_30.getValue());
            } else {
                productionRecord.setReportType(optional.get().getReportType());
                productionRecord.setReportStatus(MesExtEnumUtil.REPORT_STATUS.REPORT_STATUS_10.getValue());
                productionRecord.setReportPartNo(!StringUtils.isEmpty(optional.get().getReportPartNo()) ? optional.get().getReportPartNo() : productionRecord.getPartNo());
            }
        }

        //非排序验证: 判断工单是否是试制工单
        if (productionRecord.getReportStatus().compareTo(MesExtEnumUtil.REPORT_STATUS.REPORT_STATUS_10.getValue()) == 0 &&
                workCenter.getCenterType().compareTo(MesExtEnumUtil.WORK_CENTER_TYPE.NOSORT.getValue()) == 0 &&
                null != productionPartContext && !StringUtils.isEmpty(productionPartContext.getOrderFlag()) &&
                productionPartContext.getOrderFlag().equals(MesExtEnumUtil.ORDER_TYPE_IDENTIFICATION.P.getValue())) {
            productionRecord.setReportStatus(MesExtEnumUtil.REPORT_STATUS.REPORT_STATUS_30.getValue());
        }

        //非排序与排序 相同验证: 判断是否已经存在汇报状态的加工记录
        if (productionRecord.getReportStatus().compareTo(MesExtEnumUtil.REPORT_STATUS.REPORT_STATUS_10.getValue()) == 0 && isSamePart(productionPsInContext, productionPsOutContext) &&
                checkPsIsReported(reqBean.getOrganizeCode(), productionPsOutContext.getProductSn(), productionPsOutContext.getPartNo())) {
            productionRecord.setReportStatus(MesExtEnumUtil.REPORT_STATUS.REPORT_STATUS_30.getValue());
        }

        productionRecord.setModuleStatisticsStatus(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue());

        productionRecord.setAreaCode(reqBean.getAreaCode());
        productionRecord.setWorkCenterCode(reqBean.getWorkCenterCode());
        productionRecord.setWorkCellCode(reqBean.getWorkCellCode());
        productionRecord.setProcessCode(reqBean.getProcessCode());
        productionRecord.setCraftCode(productionProcessContext.getCraftCode());

        if (null != scanMonitorContext) {
            productionRecord.setMouldRecordId(scanMonitorContext.getMouldRecordId());
            productionRecord.setStartDateTime(scanMonitorContext.getStartDateTime());
        }

        productionRecord.setIsComplete(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue());

        productionRecord.setOrganizeCode(reqBean.getOrganizeCode());
        ConvertBean.serviceModelInitialize(productionRecord, reqBean.getUserInfo());
        productionRecord.setCompleteDateTime(productionRecord.getModifyDatetime());
        productionRecord.setCreateDatetime((new SimpleDateFormat(MesPcnExtConstWords.DATE_FORMAT_SSS)).format(new Date()));
        productionRecord.setModifyDatetime(productionRecord.getCreateDatetime());

        productionRecord.setFid(UUID.randomUUID().toString());
        productionRecord.setOneMouldMoreId(UUID.randomUUID().toString());

        //排序可能会先赋加工记录ID, 装配件记录前置工步写入时需要写加工记录ID
        if (!StringUtils.isEmpty(prodRuleContext.getProductionRecordId())) productionRecord.setId(prodRuleContext.getProductionRecordId());

        productionRecord = productionRecordRepository.insert(productionRecord);

        //判断加工规则有没有赋值加工记录ID或者模具号
        if (null != prodRuleContext && (StringUtils.isEmpty(prodRuleContext.getProductionRecordId()) || StringUtils.isEmpty(prodRuleContext.getMouldNo()))) {
            prodRuleContextList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getForeignKey()) && o.getForeignKey().compareTo(productionPsOutContext.getForeignKey()) == 0)).findFirst().get().productionRecordId(productionRecord.getId()).mouldNo(mouldNo);
        }

    }

    //加工规则中进料零件与产出零件是否一致
    private Boolean isSamePart(MesProductionPsInContext productionPsInContext, MesProductionPsOutContext productionPsOutContext) {
        if (null == productionPsInContext) return false;
        if (StringUtils.isEmpty(productionPsInContext.getPartNo())) return false;
        if (null == productionPsOutContext) return false;
        if (!productionPsInContext.getPartNo().equals(productionPsOutContext.getPartNo())) return false;
        return true;
    }

    //验证是否存在产出零件条码+零件编码已经汇报的场景
    private Boolean checkPsIsReported(String organizeCode, String productSn, String partNo) {
        List<MesProductionRecord> productionRecordList = productionRecordService.findProductionRecordList(organizeCode, productSn, partNo);
        if (CollectionUtils.isEmpty(productionRecordList)) return false;
        Optional<MesProductionRecord> optional = productionRecordList.stream().filter(o -> (null != o && o.getReportStatus().compareTo(MesExtEnumUtil.REPORT_STATUS.REPORT_STATUS_30.getValue()) != 0)).findFirst();
        return (null != optional && optional.isPresent()) ? true : false;
    }

    //获取模具号
    private String getMouldNo(StationRequestBean reqBean, MesWorkCenter workCenter, List<MesProdRuleContext> prodRuleContextList) {
        //非排序 先获取头道模具号, 没有再获取模具号
        if (workCenter.getCenterType().compareTo(MesExtEnumUtil.WORK_CENTER_TYPE.NOSORT.getValue()) == 0) {
            MesEquipVariableCollectContext equipVariableCollectContext = productionDispatchContextStepService.getFirstMouldNoContext(reqBean);
            if (null == equipVariableCollectContext) equipVariableCollectContext = productionDispatchContextStepService.getMouldNoContext(reqBean);
            return null != equipVariableCollectContext ? equipVariableCollectContext.getEquipVariableValue() : null;
        }
        //排序, 加工规则上下文中可能已经存了模具号, 装配件前置绑定的时候会写模具号
        Optional<MesProdRuleContext> optional = prodRuleContextList.stream().filter(o -> null != o && !StringUtils.isEmpty(o.getMouldNo())).findFirst();
        if (null != optional && optional.isPresent()) return optional.get().getMouldNo();
        MesEquipVariableCollectContext equipVariableCollectContext = productionDispatchContextStepService.getMouldNoContext(reqBean);
        return null != equipVariableCollectContext ? equipVariableCollectContext.getEquipVariableValue() : null;
    }

}
