package cn.estsh.i3plus.ext.mes.pcn.pojo.context;

import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.mes.bean.MesEquipmentVariable;
import cn.estsh.i3plus.pojo.mes.bean.MesEquipmentVariableCfg;
import cn.estsh.i3plus.pojo.mes.bean.MesWorkCell;
import cn.estsh.i3plus.pojo.mes.bean.MesWorkCenter;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.ApiParam;
import lombok.Data;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;
import java.util.stream.Collectors;

/**
 * 生产过程上下文对象
 */
@Data
public class MesProductionProcessContext implements Serializable {

    private static final long serialVersionUID = -622564192243157366L;

    @ApiParam("结果")
    private Boolean success;

    @ApiParam("信息")
    private String message;

    @ApiParam("是否需要重新存储")
    private Boolean isNeedCache;

    @ApiParam("是否存在加工不可用规则")
    private String prodRuleIgnoreCfg;

    @ApiParam("组织代码")
    private String organizeCode;

    @ApiParam("finishCode码")
    private String finishCode;

    @ApiParam("工艺强过码")
    private String craftJumpCode;

    @ApiParam("装配件跳过码")
    private String assemblySkipCode;

    @ApiParam("装配件整腔跳过码")
    private String assemblyCavitySkipCode;

    @ApiParam("排序线可疑码")
    private String sortSuspiciousCode;

    @ApiParam("生产线信息([Json]MesWorkCenter)")
    private String workCenterJson;

    @ApiParam("工位信息([Json]MesWorkCell)")
    private String workCellJson;

    @ApiParam("工位设备信息([Json]List<MesCellEquipContext>)")
    private String cellEquipListJson;

    @ApiParam("工序代码")
    private String processCode;

    @ApiParam("工序名称")
    private String processName;

    @ApiParam("工艺代码")
    private String craftCode;

    @ApiParam("工艺名称")
    private String craftName;

    @ApiParam("当前工位设备对象([Json]MesCellEquipContext)")
    private String curCellEquipJson;

    @ApiParam("变量接口逻辑信息([Json]List<MesEquipmentVariableCfg>)")
    private String equipVariableCfgJson;

    @ApiParam("设备变量集合信息([Json]List<MesEquipmentVariable>)")
    private String equipVariableJson;

    //---------------------- 构造方法 ---------------------------------------

    public MesProductionProcessContext() {}

    public MesProductionProcessContext(String organizeCode) {
        this.organizeCode = organizeCode;
    }

    //---------------------- 信息初始化/赋值 ---------------------------------------

    //上下文信息结果初始化
    public MesProductionProcessContext success() {
        this.success = true;
        this.isNeedCache = false;
        this.message = null;
        return this;
    }

    //手动赋结果
    public MesProductionProcessContext success(Boolean success) {
        this.success = success;
        return this;
    }

    //手动赋是否缓存的标志（大部分工步最后都会保存上下文,最终实际根据此标志识别是否需要保存）
    public MesProductionProcessContext isNeedCache() {
        this.isNeedCache = true;
        return this;
    }

    //手动赋是否存在加工不可用规则
    public MesProductionProcessContext prodRuleIgnoreCfg(String prodRuleIgnoreCfg) {
        this.prodRuleIgnoreCfg = prodRuleIgnoreCfg;
        return this;
    }

    //上下文信息结果信息赋值后给工步使用
    public MesProductionProcessContext message(String message) {
        this.success = false;
        this.message = message;
        return this;
    }

    //---------------------- 生产过程控制全局密码 ---------------------------------------

    //上下文赋值finishCode码
    public MesProductionProcessContext finishCode(String finishCode) {
        this.finishCode = finishCode;
        return this.isNeedCache();
    }

    //上下文赋值工艺强过码
    public MesProductionProcessContext craftJumpCode(String craftJumpCode) {
        this.craftJumpCode = craftJumpCode;
        return this.isNeedCache();
    }

    //上下文赋值装配件跳过码
    public MesProductionProcessContext assemblySkipCode(String assemblySkipCode) {
        this.assemblySkipCode = assemblySkipCode;
        return this.isNeedCache();
    }

    //上下文赋值装配件整腔跳过码
    public MesProductionProcessContext assemblyCavitySkipCode(String assemblyCavitySkipCode) {
        this.assemblyCavitySkipCode = assemblyCavitySkipCode;
        return this.isNeedCache();
    }

    //排序线可疑码
    public MesProductionProcessContext sortSuspiciousCode(String sortSuspiciousCode) {
        this.sortSuspiciousCode = sortSuspiciousCode;
        return this.isNeedCache();
    }


    //---------------------- 生产线对象 ---------------------------------------

    //从上下文中取出生产线对象
    public MesWorkCenter getWorkCenter() {
        return !StringUtils.isEmpty(this.workCenterJson) ? JSONObject.parseObject(this.workCenterJson, MesWorkCenter.class) : null;
    }

    //上下文赋值生产线对象
    public MesProductionProcessContext workCenterJson(MesWorkCenter workCenter) {
        if (StringUtils.isEmpty(workCenter.getIsCheckOrderQty())) workCenter.setIsCheckOrderQty(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue());
        if (StringUtils.isEmpty(workCenter.getIsIgnoreQc())) workCenter.setIsCheckOrderQty(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue());
        if (StringUtils.isEmpty(workCenter.getIsPushQueue())) workCenter.setIsPushQueue(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue());
        this.workCenterJson = null != workCenter ? JSONObject.toJSONString(workCenter) : null;
        return this.isNeedCache();
    }

    //---------------------- 工位对象 ---------------------------------------

    //从上下文中取出工位对象
    public MesWorkCell getWorkCell() {
        return !StringUtils.isEmpty(this.workCellJson) ? JSONObject.parseObject(this.workCellJson, MesWorkCell.class) : null;
    }

    //上下文赋值工位对象
    public MesProductionProcessContext workCellJson(MesWorkCell workCell) {
        if (StringUtils.isEmpty(workCell.getIsCheckSeq())) workCell.setIsCheckSeq(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue());
        if (StringUtils.isEmpty(workCell.getIsCheckCraft())) workCell.setIsCheckCraft(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue());
        if (StringUtils.isEmpty(workCell.getIsSeqScan())) workCell.setIsCheckSeq(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue());
        if (StringUtils.isEmpty(workCell.getIsResetScan())) workCell.setIsResetScan(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue());
        if (StringUtils.isEmpty(workCell.getNoCalcOrderQty())) workCell.setNoCalcOrderQty(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue());
        if (StringUtils.isEmpty(workCell.getIsEndWorkCell())) workCell.setIsEndWorkCell(CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue());
        this.workCellJson = null != workCell ? JSONObject.toJSONString(workCell) : null;
        return this.isNeedCache();
    }

    //---------------------- 工序/工艺信息 ---------------------------------------

    //上下文赋值工序信息
    public MesProductionProcessContext processCode(String processCode, String processName) {
        this.processCode = processCode;
        this.processName = processName;
        return this.isNeedCache();
    }

    //上下文赋值工艺信息
    public MesProductionProcessContext craftCode(String craftCode, String craftName) {
        this.craftCode = craftCode;
        this.craftName = craftName;
        return this.isNeedCache();
    }

    //---------------------- 工位设备对象集合 ---------------------------------------

    //从上下文中取出工位设备对象集合
    private List<MesCellEquipContext> getCellEquipList() {
        return !StringUtils.isEmpty(this.cellEquipListJson) ? JSONObject.parseArray(this.cellEquipListJson, MesCellEquipContext.class) : null;
    }

    //上下文赋值工位设备对象集合
    public MesProductionProcessContext cellEquipListJson(List<MesCellEquipContext> cellEquipList) {
        this.cellEquipListJson = !CollectionUtils.isEmpty(cellEquipList) ? JSONObject.toJSONString(cellEquipList) : null;
        return this.isNeedCache();
    }

    //---------------------- 工位当前设备 ---------------------------------------

    //从上下文中的工位设备对象集合中取出当前要使用的设备
    public MesCellEquipContext filterCurCellEquip() {
        List<MesCellEquipContext> cellEquipList = getCellEquipList();
        if (CollectionUtils.isEmpty(cellEquipList) || cellEquipList.size() == 1) return filterCurCellEquip(cellEquipList);
        return filterCurCellEquip(cellEquipList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getSeq()))).sorted(Comparator.comparing(MesCellEquipContext::getSeq)).collect(Collectors.toList()));
    }

    //从上下文中的工位设备对象集合中根据设备代码取出当前要使用的设备
    public MesCellEquipContext filterCurCellEquip(String equipmentCode) {
        if (StringUtils.isEmpty(equipmentCode)) return filterCurCellEquip();
        List<MesCellEquipContext> cellEquipList = getCellEquipList();
        return filterCurCellEquip(CollectionUtils.isEmpty(cellEquipList) ? null : cellEquipList.stream().filter(o -> (null != o && o.getEquipmentCode().equals(equipmentCode))).collect(Collectors.toList()));
    }

    //从上下文中的工位设备对象集合中取出第一个设备
    private MesCellEquipContext filterCurCellEquip(List<MesCellEquipContext> cellEquipContextList) {
        return !CollectionUtils.isEmpty(cellEquipContextList) ? cellEquipContextList.get(0) : null;
    }

    //从上下文中取出工位当前要使用的设备
    public MesCellEquipContext getCurCellEquip() {
        return !StringUtils.isEmpty(this.curCellEquipJson) ? JSONObject.parseObject(this.curCellEquipJson, MesCellEquipContext.class) : null;
    }

    //上下文赋值工位当前要使用的设备
    public MesProductionProcessContext curCellEquipJson(MesCellEquipContext curEquip) {
        //未配置则默认1腔
        if (StringUtils.isEmpty(curEquip.getCavity()) || curEquip.getCavity().compareTo(MesPcnExtConstWords.ZERO) == 0) curEquip.setCavity(MesPcnExtConstWords.ONE);
        //未配置则默认没有装配件
        if (StringUtils.isEmpty(curEquip.getBindQty())) curEquip.setBindQty(MesPcnExtConstWords.ZERO);
        this.curCellEquipJson = null != curEquip ? JSONObject.toJSONString(curEquip) : null;
        return this.isNeedCache();
    }

    //---------------------- 数据变量接口逻辑集合 ---------------------------------------

    //从上下文中取出设备数据变量接口逻辑集合
    private List<MesEquipmentVariableCfg> getEquipVariableCfgList() {
        return !StringUtils.isEmpty(this.equipVariableCfgJson) ? JSONObject.parseArray(this.equipVariableCfgJson, MesEquipmentVariableCfg.class) : null;
    }

    //从上下文的设备数据变量接口逻辑对象集合中取出当前设备信息的逻辑类型对应的接口逻辑对象集合
    public List<MesEquipmentVariableCfg> getEquipVariableCfgListByVct() {
        MesCellEquipContext cellEquipContext = getCurCellEquip();
        return null != cellEquipContext ? getEquipVariableCfgListByVct(cellEquipContext.getVariableCfgType()) : null;
    }

    //从上下文的设备数据变量接口逻辑对象集合中取出当前设备信息的逻辑类型对应的接口逻辑对象集合
    public List<MesEquipmentVariableCfg> getEquipVariableCfgListByVct(String variableCfgType) {
        List<MesEquipmentVariableCfg> equipmentVariableCfgList = getEquipVariableCfgList();
        return (StringUtils.isEmpty(variableCfgType) || CollectionUtils.isEmpty(equipmentVariableCfgList)) ? null :
                equipmentVariableCfgList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getCategoryLevelTwo()) && o.getVariableCfgType().equals(variableCfgType))).collect(Collectors.toList());
    }

    //上下文赋值数据变量接口逻辑对象集合
    public MesProductionProcessContext equipVariableCfgJson(List<MesEquipmentVariableCfg> equipmentVariableCfgList) {
        if (CollectionUtils.isEmpty(equipmentVariableCfgList)) return this;
        if (!StringUtils.isEmpty(this.equipVariableCfgJson)) equipmentVariableCfgList.addAll(getEquipVariableCfgList());
        equipmentVariableCfgList.stream().filter(o -> null != o).forEach(o -> {
            if (StringUtils.isEmpty(o.getModifyDatetime())) o.setModifyDatetime(o.getCreateDatetime());
        });
        equipmentVariableCfgList = equipmentVariableCfgList.stream().filter(o -> null != o).sorted(Comparator.comparing(MesEquipmentVariableCfg::getModifyDatetime).reversed()).collect(Collectors.toList());
        equipmentVariableCfgList = equipmentVariableCfgList.stream().filter(o -> null != o).distinct().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(MesEquipmentVariableCfg::getId))), ArrayList::new));
        this.equipVariableCfgJson = JSONObject.toJSONString(equipmentVariableCfgList);
        return this.isNeedCache();
    }

    //---------------------- 数据变量对象集合 ---------------------------------------

    //从上下文中取出设备数据变量对象集合
    private List<MesEquipmentVariable> getEquipVariableList() {
        return !StringUtils.isEmpty(this.equipVariableJson) ? JSONObject.parseArray(this.equipVariableJson, MesEquipmentVariable.class) : null;
    }

    //从上下文的设备数据变量对象集合中取出当前设备对应具体变量类型的数据变量对象集合
    public List<MesEquipmentVariable> getEquipVariableListByEquVt(Integer variableType) {
        MesCellEquipContext cellEquipContext = getCurCellEquip();
        return (null != cellEquipContext && !StringUtils.isEmpty(variableType)) ? getEquipVariableListByEquVt(cellEquipContext.getEquipmentCode(), variableType) : null;
    }

    //从上下文的设备数据变量对象集合中取出当前设备对应具体变量类型的数据变量对象集合
    public List<MesEquipmentVariable> getEquipVariableListByEquVt(String equipmentCode, Integer variableType) {
        List<MesEquipmentVariable> equipmentVariableList = getEquipVariableList();
        return (StringUtils.isEmpty(equipmentCode) || null == variableType || CollectionUtils.isEmpty(equipmentVariableList)) ? null :
                equipmentVariableList.stream().filter(o -> (null != o && o.getEquipmentCode().equals(equipmentCode) && o.getVariableType().compareTo(variableType) == 0)).collect(Collectors.toList());
    }

    //上下文赋值数据变量对象集合
    public MesProductionProcessContext equipVariableJson(List<MesEquipmentVariable> equipmentVariableList) {
        equipmentVariableList = CollectionUtils.isEmpty(equipmentVariableList) ? null : equipmentVariableList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getCategoryLevelTwo()))).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(equipmentVariableList)) return this;
        if (!StringUtils.isEmpty(this.equipVariableJson)) equipmentVariableList.addAll(getEquipVariableList());
        equipmentVariableList.stream().filter(o -> null != o).forEach(o -> {
            if (StringUtils.isEmpty(o.getModifyDatetime())) o.setModifyDatetime(o.getCreateDatetime());
        });
        equipmentVariableList = equipmentVariableList.stream().filter(o -> null != o).sorted(Comparator.comparing(MesEquipmentVariable::getModifyDatetime).reversed()).collect(Collectors.toList());
        equipmentVariableList = equipmentVariableList.stream().filter(o -> null != o).distinct().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(MesEquipmentVariable::getId))), ArrayList::new));
        this.equipVariableJson = JSONObject.toJSONString(equipmentVariableList);
        return this.isNeedCache();
    }

}
