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

import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.mes.bean.MesProdRuleNosortCfg;
import cn.estsh.i3plus.pojo.mes.bean.MesWorkCenter;
import cn.estsh.i3plus.pojo.mes.util.MesExtEnumUtil;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.ApiParam;
import lombok.Data;
import org.springframework.beans.BeanUtils;
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.Optional;
import java.util.stream.Collectors;

/**
 * 生产过程上下文对象-产品加工规则
 */
@Data
public class MesProdRuleContext implements Serializable {

    private static final long serialVersionUID = 1522652732930288854L;

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

    @ApiParam(name = "数据关联键")
    private Integer foreignKey;

    @ApiParam("加工记录ID")
    private Long productionRecordId;

    @ApiParam("模具号")
    private String mouldNo;

    @ApiParam(name = "工单号,不一定有值")
    private String workOrderNo;

    @ApiParam(name = "读/扫主条码信息(内制件/外协件/排序条码即工单号),不一定有值")
    private String productSn;

    @ApiParam("装配件绑定清单  [JSON]List<MesProductionAssemblyContext>")
    public String assemblyDataJson;

    @ApiParam("生产线代码")
    public String workCenterCode;

    @ApiParam("工位代码")
    public String workCellCode;

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

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

    @ApiParam(name = "是否验证装配件扫描顺序")
    private Integer isCheckBindSeq;

    //-------以下非排序属性-------------

    @ApiParam("非排序产品加工规则ID")
    public Long pid;

    @ApiParam(name = "进料零件号")
    private String inPartNo;

    @ApiParam(name = "产成零件号")
    private String outPartNo;

    @ApiParam(name = "设备代码")
    private String equipmentCode;

    @ApiParam(name = "进料零件规则")
    private String inPartNoRule;

    @ApiParam(name = "是否打印条码")
    private Integer isPrint;

    @ApiParam(name = "是否有装配件")
    private Integer isHasBind;

    //非排序报工方式 只有 汇报 或者 移库 二选一
    @ApiParam(name = "汇报方式")
    private Integer reportType;

    @ApiParam(name = "是否包装")
    private Integer isPackage;

    @ApiParam(name = "是否打印包装条码")
    private Integer isPrintPackage;

    @ApiParam(name = "成品站点")
    private String partLocation;

    @ApiParam(name = "子箱设备信号点")
    private String packageEquSignal;

    @ApiParam("不可用规则")
    private String prodRuleIgnoreCfg;

    //----------仅作为查询条件冗余-------------

    @ApiParam(name = "进料零件号是否有值")
    private Boolean inPartIsEmpty;

    @ApiParam(name = "进料规则是否有值")
    private Boolean inPartRuleIsEmpty;

    @ApiParam(name = "进料零件号")
    private String inPartNos;

    @ApiParam(name = "产成零件号")
    private String outPartNos;

    //显示前道所有装配件工步写的工位代码对应值的JSON信息, 显示装配件工步写的工艺顺序号对应值的JSON信息
    @ApiParam(name = "平行 工位/工艺顺序号")
    private String parallelInfo;

    @ApiParam(name = "是否存在装配件容器匹配")
    private String isMatchContainer;

    @ApiParam(name = "是否存在装配件原料调配")
    private String isMatchRawMix;

    //用于弹框输入工单数量
    @ApiParam(name = "每腔数量")
    private Double eachCavityQty = new Double(1);

    public MesProdRuleContext() {}

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

    public MesProdRuleContext(String organizeCode, String workCenterCode, String workCellCode, String processCode, String craftCode) {
        this.organizeCode = organizeCode;
        this.workCenterCode = workCenterCode;
        this.workCellCode = workCellCode;
        this.processCode = processCode;
        this.craftCode = craftCode;
    }

    public MesProdRuleContext copy(MesProdRuleNosortCfg prodRuleNosortCfg) {
        BeanUtils.copyProperties(prodRuleNosortCfg, this);
        this.pid = prodRuleNosortCfg.getId();
        if (!StringUtils.isEmpty(this.inPartNo)) this.inPartNo = this.inPartNo.toUpperCase();
        if (!StringUtils.isEmpty(this.outPartNo)) this.outPartNo = this.outPartNo.toUpperCase();
        return this;
    }

    //非排序无须使用工位的字段,直接使用非排序产品加工规则的字段;
    //排序使用工位的字段,  如果是显示前道所有装配件场景下在装配件清单中单独标记各个工位的装配件是否需要顺序扫描
    public MesProdRuleContext isCheckBindSeq(Integer isSeqScan) {
        if (!StringUtils.isEmpty(isSeqScan)) this.isCheckBindSeq = isSeqScan;
        return this;
    }

    public MesProdRuleContext workOrderNo(String workOrderNo) {
        this.workOrderNo = workOrderNo;
        return this;
    }

    public MesProdRuleContext productSn(String productSn) {
        this.productSn = productSn;
        return this;
    }

    public MesProdRuleContext foreignKey(Integer foreignKey) {
        this.foreignKey = foreignKey;
        return this;
    }

    public MesProdRuleContext productionRecordId(Long productionRecordId) {
        this.productionRecordId = productionRecordId;
        return this;
    }

    public MesProdRuleContext mouldNo(String mouldNo) {
        this.mouldNo = mouldNo;
        return this;
    }

    public MesProdRuleContext inPartIsEmpty(Boolean isEmpty) {
        this.inPartIsEmpty = isEmpty;
        return this;
    }

    public MesProdRuleContext inPartRuleIsEmpty(Boolean isEmpty) {
        this.inPartRuleIsEmpty = isEmpty;
        return this;
    }

    public MesProdRuleContext pid(Long pid) {
        this.pid = pid;
        return this;
    }

    public MesProdRuleContext inPartNo(String inPartNo) {
        this.inPartNo = inPartNo;
        return this;
    }

    public MesProdRuleContext outPartNo(String outPartNo) {
        this.outPartNo = outPartNo;
        return this;
    }

    public MesProdRuleContext inPartNos(List<String> inPartNoList) {
        if (CollectionUtils.isEmpty(inPartNoList)) return this;
        inPartNoList = inPartNoList.stream().filter(o -> !StringUtils.isEmpty(o)).distinct().collect(Collectors.toList());
        if (inPartNoList.size() > 1) this.inPartNos = JSONObject.toJSONString(inPartNoList);
        else this.inPartNo = inPartNoList.get(0);
        return this;
    }

    public MesProdRuleContext outPartNos(List<String> outPartNoList) {
        if (CollectionUtils.isEmpty(outPartNoList)) return this;
        outPartNoList = outPartNoList.stream().filter(o -> !StringUtils.isEmpty(o)).distinct().collect(Collectors.toList());
        if (outPartNoList.size() > 1) this.outPartNos = JSONObject.toJSONString(outPartNoList);
        else this.outPartNo = outPartNoList.get(0);
        return this;
    }

    public List<String> getInPartNoList() {
        return !StringUtils.isEmpty(this.inPartNos) ? JSONObject.parseObject(this.inPartNos, List.class) : null;
    }

    public List<String> getOutPartNoList() {
        return !StringUtils.isEmpty(this.outPartNos) ? JSONObject.parseObject(this.outPartNos, List.class) : null;
    }

    public MesProdRuleContext equipmentCode(String equipmentCode) {
        this.equipmentCode = equipmentCode;
        return this;
    }

    public MesProdRuleContext eachCavityQty(String eachCavityQty) {
        if (StringUtils.isEmpty(eachCavityQty)) return this;
        return eachCavityQty(new Double(eachCavityQty));
    }

    public MesProdRuleContext eachCavityQty(Double eachCavityQty) {
        if (StringUtils.isEmpty(eachCavityQty) || eachCavityQty.compareTo(new Double(0)) == 0) return this;
        this.eachCavityQty = eachCavityQty;
        return this;
    }

    public MesProdRuleContext assemblyDataJson(List<? extends MesProductionAssemblyContext> productionAssemblyContextList) {
        if (CollectionUtils.isEmpty(productionAssemblyContextList)) return this;
        this.assemblyDataJson = JSONObject.toJSONString(productionAssemblyContextList);
        isMatchContainer(productionAssemblyContextList);
        isMatchRawMix(productionAssemblyContextList);
        return this;
    }

    //标记装配件是否需要进行匹配容器条码进行扣减
    public MesProdRuleContext isMatchContainer(List<? extends MesProductionAssemblyContext> productionAssemblyContextList) {
        if (CollectionUtils.isEmpty(productionAssemblyContextList)) return this;
        Optional<MesProductionAssemblyContext> optional = (Optional<MesProductionAssemblyContext>) productionAssemblyContextList.stream()
                .filter(o -> (null != o && !StringUtils.isEmpty(o.getMatchType()) && o.getMatchType().compareTo(MesExtEnumUtil.ASSEMBLY_MATCH_TYPE.MATCH_TYPE_80.getValue()) == 0)).findFirst();
        if (null != optional && optional.isPresent()) this.isMatchContainer = CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValueStr();
        return this;
    }

    //标记装配件是否需要进行原料调配
    public MesProdRuleContext isMatchRawMix(List<? extends MesProductionAssemblyContext> productionAssemblyContextList) {
        if (CollectionUtils.isEmpty(productionAssemblyContextList)) return this;
        Optional<MesProductionAssemblyContext> optional = (Optional<MesProductionAssemblyContext>) productionAssemblyContextList.stream()
                .filter(o -> (null != o && !StringUtils.isEmpty(o.getMatchType()) && o.getMatchType().compareTo(MesExtEnumUtil.ASSEMBLY_MATCH_TYPE.MATCH_TYPE_90.getValue()) == 0)).findFirst();
        if (null != optional && optional.isPresent()) this.isMatchRawMix = CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValueStr();
        return this;
    }

    //根据生产线类型返回装配件数据集合
    public List<? extends MesProductionAssemblyContext> getProductionAssemblyContextList(MesWorkCenter workCenter) {
        if (StringUtils.isEmpty(this.assemblyDataJson)) return null;
        return workCenter.getCenterType().compareTo(MesExtEnumUtil.WORK_CENTER_TYPE.NOSORT.getValue()) == 0 ? getNosortAssemblyDataContext() : getSortAssemblyDataContext();
    }

    //根据生产线类型返回装配件数据集合【向上转型】
    public List<MesProductionAssemblyContext> getAssemblyDataContext(MesWorkCenter workCenter) {
        if (StringUtils.isEmpty(this.assemblyDataJson)) return null;
        List<MesProductionAssemblyContext> productionAssemblyContextList = new ArrayList<>();
        if (MesExtEnumUtil.WORK_CENTER_TYPE.SORT.getValue() == workCenter.getCenterType()) getSortAssemblyDataContext().forEach(o -> productionAssemblyContextList.add(o));
        else getNosortAssemblyDataContext().forEach(o -> productionAssemblyContextList.add(o));
        return productionAssemblyContextList;
    }

    //非排序装配件清单
    public List<MesProductionAssemblyNosortContext> getNosortAssemblyDataContext() {
        List<MesProductionAssemblyNosortContext> nosortAssemblyList = !StringUtils.isEmpty(this.assemblyDataJson) ? JSONObject.parseArray(this.assemblyDataJson, MesProductionAssemblyNosortContext.class) : null;
        return CollectionUtils.isEmpty(nosortAssemblyList) ? null : nosortAssemblyList.stream().filter(o -> null != o).sorted(Comparator.comparing(MesProductionAssemblyNosortContext::getRouteSeq)).collect(Collectors.toList());
    }

    //排序装配件清单
    public List<MesProductionAssemblySortContext> getSortAssemblyDataContext() {
        List<MesProductionAssemblySortContext> sortAssemblyList = !StringUtils.isEmpty(this.assemblyDataJson) ? JSONObject.parseArray(this.assemblyDataJson, MesProductionAssemblySortContext.class) : null;
        return CollectionUtils.isEmpty(sortAssemblyList) ? null : sortAssemblyList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getProcessSeq()))).sorted(Comparator.comparing(MesProductionAssemblySortContext::getProcessSeq).thenComparing(MesProductionAssemblySortContext::getRouteSeq)).collect(Collectors.toList());
    }

}
