package cn.ibizlab.core.data.lite;

import cn.ibizlab.core.data.dto.DataObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Getter
@Setter
@NoArgsConstructor
@JsonIgnoreProperties(value = "handler")
public class EntityModel {

    @JsonIgnore
    @JSONField(serialize = false)
    public String getEntityId() {
        return getEntity().getEntityId();
    }

    @JsonIgnore
    @JSONField(serialize = false)
    public String getCodeName() {
        return getEntity().getCodeName();
    }

    @JsonIgnore
    @JSONField(serialize = false)
    public String getEntityName() {
        return getEntity().getEntityName();
    }

    @JsonIgnore
    @JSONField(serialize = false)
    public String getTableName() {
        return getEntity().getTableName();
    }

    @JsonIgnore
    @JSONField(serialize = false)
    public String getLogicName() {
        return getEntity().getLogicName();
    }

    @JsonIgnore
    @JSONField(serialize = false)
    public String getSystemId() {
        return getEntity().getSystemId();
    }

    private MetaEntityModel entity;

    private List<MetaDataSetModel> dataSets;

    public EntityModel addDataSet(MetaDataSetModel dataSet)
    {
        if(dataSets==null)
            dataSets=new ArrayList<>();
        dataSets.add(dataSet);
        return this;
    }

    private List<FieldModel> fields;

    public EntityModel addField(FieldModel fieldModel)
    {
        if(fields==null)
            fields=new ArrayList<>();
        fields.add(fieldModel);
        return this;
    }

    private List<RelationshipModel> references;

    public EntityModel addReference(RelationshipModel relationshipModel)
    {
        if(references==null)
            references=new ArrayList<>();
        references.add(relationshipModel);
        return this;
    }

    @JsonIgnore
    @JSONField(serialize = false)
    private Map<String,RelationshipModel> refMaps;
    @JsonIgnore
    @JSONField(serialize = false)
    public Map<String,RelationshipModel> getRefMaps()
    {
        if(refMaps==null)
            refMaps=new LinkedHashMap<>();
        if(references!=null)
        {
            references.forEach(ship->{
                if(!StringUtils.isEmpty(ship.getCodeName()))
                    refMaps.put(ship.getCodeName(),ship);
                if(!StringUtils.isEmpty(ship.getRelation())) {
                    String fkname= DataObject.getStringValue(ship.getRelation().getName(),"");
                    if(!StringUtils.isEmpty(fkname))
                        refMaps.put(fkname, ship);
                }
            });
        }
        return refMaps;
    }

    private List<RelationshipModel> nesteds;

    public EntityModel addNested(RelationshipModel relationshipModel)
    {
        if(nesteds==null)
            nesteds=new ArrayList<>();
        nesteds.add(relationshipModel);
        return this;
    }

    @JsonIgnore
    @JSONField(serialize = false)
    private Map<String, FieldModel> fieldMap = null;

    @JsonIgnore
    @JSONField(serialize = false)
    public Map<String, FieldModel> getFieldMap()
    {
        if(fields!=null&&fieldMap==null)
        {
            fieldMap=new LinkedHashMap<>();
            fields.forEach(field->{
                fieldMap.put(field.getColumnName(),field);
                fieldMap.put(field.getCodeName(),field);
            });
        }
        return fieldMap;
    }

    @JsonIgnore
    @JSONField(serialize = false)
    private FieldModel lastModifyField;
    @JsonIgnore
    @JSONField(serialize = false)
    public FieldModel getLastModifyField() {
        if(fields!=null&&lastModifyField==null)
            for(FieldModel fieldModel:fields)
                if(fieldModel.isLastModifyField())
				{
					lastModifyField=fieldModel;
					return lastModifyField;
				}
        return lastModifyField;
    }

	@JsonIgnore
	@JSONField(serialize = false)
    private boolean isLogicValid=true;

    @JsonIgnore
    @JSONField(serialize = false)
    public boolean isLogicValid()
    {
        if(isLogicValid&&logicValidField==null) {
            if (fields != null) {
                for (FieldModel fieldModel : fields) {
                    if (fieldModel.isLogicValidField()) {
                        logicValidField = fieldModel;
                        return isLogicValid;
                    }
                }
            }
            isLogicValid = false;
        }
        return isLogicValid;
    }
	@JsonIgnore
	@JSONField(serialize = false)
    private FieldModel logicValidField;
	@JsonIgnore
	@JSONField(serialize = false)
	public FieldModel getLogicValidField() {
		if(isLogicValid&&logicValidField==null) {
			if (fields != null) {
				for (FieldModel fieldModel : fields) {
					if (fieldModel.isLogicValidField()) {
						logicValidField = fieldModel;
						return logicValidField;
					}
				}
			}
			isLogicValid = false;
		}
		return logicValidField;
	}

	@JsonIgnore
	@JSONField(serialize = false)
	private String logicVal;
	@JsonIgnore
	@JSONField(serialize = false)
	public String getLogicVal()
	{
		if(StringUtils.isEmpty(logicVal))
		    logicVal=this.getExtParams("logicval");
		if(StringUtils.isEmpty(logicVal))
			logicVal="1";
		return logicVal;
	}
	@JsonIgnore
	@JSONField(serialize = false)
	private String logicDelVal;
	@JsonIgnore
	@JSONField(serialize = false)
	public String getLogicDelVal()
	{
		if(StringUtils.isEmpty(logicVal))
			logicDelVal=this.getExtParams("logicdelval");
		if(StringUtils.isEmpty(logicDelVal))
			logicDelVal="0";
		return logicDelVal;
	}
	@JsonIgnore
	@JSONField(serialize = false)
	private FieldModel keyField;
    @JsonIgnore
    @JSONField(serialize = false)
    public FieldModel getKeyField() {
        if(fields!=null&&keyField==null)
            for(FieldModel fieldModel:fields)
                if(fieldModel.isKeyField()) {
					keyField=fieldModel;
					return keyField;
				}
        return keyField;
    }

	@JsonIgnore
	@JSONField(serialize = false)
    private List<FieldModel> unionKeyFields;
	@JsonIgnore
	@JSONField(serialize = false)
	public List<FieldModel> getUnionKeyFields() {
		if(fields!=null&&unionKeyFields==null) {
			unionKeyFields = new ArrayList<>();
			for (FieldModel fieldModel : fields)
				if (fieldModel.isUnionKeyField())
					unionKeyFields.add(fieldModel);
		}
		return unionKeyFields;
	}

    @JsonIgnore
    @JSONField(serialize = false)
    public List<FieldModel> getKeyFields() {
        if(this.getKeyField()!=null&&this.getKeyField().isPhysicalField()) {
            List<FieldModel> keyFields = new ArrayList<>();
            keyFields.add(getKeyField());
            return keyFields;
        }
        else
            return getUnionKeyFields();
    }

    public FieldModel getField(String name)
    {
        if(StringUtils.isEmpty(name))
            return null;
        if(fields==null)
            return null;
        if(getFieldMap()!=null)
            return getFieldMap().get(name);
        return null;
    }

    @JsonIgnore
    @JSONField(serialize = false)
    public String getDefaultQueryScript()
    {
        if(this.getDataSets()!=null)
        {
            for(MetaDataSetModel set:this.getDataSets()){
                if(StringUtils.isEmpty(set.getDsCode()))
                    continue;
                if("view".equalsIgnoreCase(set.getDatasetId())||
                        set.getDatasetId().startsWith("dq-view-")||
                        set.getDatasetId().startsWith(getEntityName().toLowerCase()+"-dq-view-"))
                {
                    return set.getDsCode().replace("`","").replace("[","").replace("]","");
                }
            }
            for(MetaDataSetModel set:this.getDataSets()){
                if(StringUtils.isEmpty(set.getDsCode()))
                    continue;
                if("default".equalsIgnoreCase(set.getDatasetId())||
                        set.getDatasetId().startsWith("dq-default-")||
                        set.getDatasetId().startsWith(getEntityName().toLowerCase()+"-dq-default-"))
                {
                    return set.getDsCode().replace("`","").replace("[","").replace("]","");
                }
            }
        }
        return "";
    }

    public String getSqlSegment(String dataSet)
    {

        if("CORE".equalsIgnoreCase(dataSet))
        {
            String columnSet=this.getKeyField().getColumnExp();
            for(FieldModel fieldModel:this.getUnionKeyFields())
			{
				String columnExp=fieldModel.getColumnExp();
				if(StringUtils.isEmpty(columnExp))
					continue;
				columnSet = columnSet + "," + columnExp;
			}

            return "select "+columnSet+" from "+this.getTableName()+" ";
        }
        else if("COUNT".equalsIgnoreCase(dataSet))
        {
            return "select count(1) from "+this.getTableName()+" ";
        }
        else if(this.getDataSets()!=null)
        {
            for(MetaDataSetModel set:this.getDataSets()){
                if(StringUtils.isEmpty(set.getDsCode()))
                    continue;
                if(dataSet.equalsIgnoreCase(set.getDatasetId())||
                        set.getDatasetId().indexOf("ds-"+dataSet.toLowerCase()+"-")>=0||
                        set.getDatasetId().startsWith(getEntityName().toLowerCase()+"-ds-"+dataSet.toLowerCase()+"-"))
                {
                    return set.getDsCode().replace("`","").replace("[","").replace("]","");
                }
            }

            for(MetaDataSetModel set:this.getDataSets()){
                if(StringUtils.isEmpty(set.getDsCode()))
                    continue;
                if(dataSet.equalsIgnoreCase(set.getDatasetId())||
                        set.getDatasetId().indexOf("dq-"+dataSet.toLowerCase()+"-")>=0||
                        set.getDatasetId().startsWith(getEntityName().toLowerCase()+"-dq-"+dataSet.toLowerCase()+"-"))
                {
                    return set.getDsCode().replace("`","").replace("[","").replace("]","");
                }
            }
        }

        if(dataSet.equalsIgnoreCase("VIEW")||dataSet.equalsIgnoreCase("DEFAULT"))
        {
            return "";
        }
        else
        {
            String columnSet="";
            for(FieldModel fieldModel:fields)
            {
                String columnExp=fieldModel.getColumnExp();
                if(StringUtils.isEmpty(columnExp))
                    continue;
                if(!StringUtils.isEmpty(columnSet)){
                    columnSet=columnSet+",";
                }
                columnSet=columnSet+columnExp;
            }

            return "select "+columnSet+" from "+this.getTableName()+" t ";
        }

    }

    @JsonIgnore
    @JSONField(serialize = false)
    public String getMergeColumnSegment()
    {
        String sql="";
        boolean first=true;
        for(FieldModel fieldModel:this.getFields())
        {
            if(!fieldModel.isPhysicalField())
                continue;
            if(first)
                first=false;
            else
                sql+=",";
            sql+=("#{item."+fieldModel.getColumnName().toUpperCase()+"} "+fieldModel.getColumnName().toUpperCase());
        }
        return sql;
    }

    @JsonIgnore
    @JSONField(serialize = false)
    public String getMergeSegment()
    {
        String sql="";


        sql+=   " ON (";
        boolean first=true;
        for(FieldModel fieldModel:this.getKeyFields())
        {
            if(!fieldModel.isPhysicalField())
                continue;
            if(first)
                first=false;
            else
                sql+=" and ";
            sql+=("T1."+fieldModel.getColumnName().toUpperCase()+"=T2."+fieldModel.getColumnName().toUpperCase());
        }

        sql+=")\n" +
                "  WHEN NOT MATCHED THEN INSERT(";
        first=true;
        for(FieldModel fieldModel:this.getFields())
        {
            if(!fieldModel.isPhysicalField())
                continue;
            if(first)
                first=false;
            else
                sql+=",";
            sql+=(fieldModel.getColumnName().toUpperCase());
        }
        sql+=") VALUES (" ;
        first=true;
        for(FieldModel fieldModel:this.getFields())
        {
            if(!fieldModel.isPhysicalField())
                continue;
            if(first)
                first=false;
            else
                sql+=",";
            sql+=("T2."+fieldModel.getColumnName().toUpperCase());
        }
        sql+=")\n" +
                "  WHEN MATCHED THEN UPDATE SET " ;
        first=true;
        for(FieldModel fieldModel:this.getFields())
        {
            if(!fieldModel.isPhysicalField())
                continue;
            if(fieldModel.isKeyField())
                continue;
            if(fieldModel.isUnionKeyField())
                continue;
            if(first)
                first=false;
            else
                sql+=",";
            sql+=("T1."+fieldModel.getColumnName().toUpperCase()+"=T2."+fieldModel.getColumnName().toUpperCase());
        }

        return sql;
    }

    @JsonIgnore
    @JSONField(serialize = false)
    public String getDsName()
    {
        String dsName=this.getEntity().getDsId();
        if(StringUtils.isEmpty(dsName))
        {
            dsName=this.getSystemId()+"-master";
        }
        return dsName;
    }


    public String getExtParams(String key)
	{
        return DataObject.getStringValue(entity.get(key),"");
	}

    public String getTableName(String dsType)
    {
        return DataObject.getStringValue(entity.get("table-"+dsType.toLowerCase()),getTableName());
    }

    @JsonIgnore
    @JSONField(serialize = false)
    public List<String> getDsTypes()
    {
        List<String> dsTypes=new ArrayList<>();
        String strDsTypes=DataObject.getStringValue(entity.get("ds_types"),"");
        for(String dsType:strDsTypes.split(","))
            dsTypes.add(dsType);
        return dsTypes;
    }


}
