package cn.ibizlab.core.data.domain;

import java.util.*;

import cn.ibizlab.core.data.dto.BaseData;
import cn.ibizlab.core.data.model.POSchema;
import cn.ibizlab.core.data.model.PojoSchema;
import cn.ibizlab.core.data.model.TransUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.springframework.util.ObjectUtils;
import cn.ibizlab.util.helper.DataObject;
import java.io.Serializable;
import lombok.*;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.util.StringUtils;


/**
 * [业务实体] 对象
 */
@Builder
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ApiModel("业务实体")
public class DOModel implements Serializable {

    /**
     * 标识
     */
    @JSONField(name = "id")
    @JsonProperty("id")
    @ApiModelProperty("标识")
    private String id;

    /**
     * 名称
     */
    @JSONField(name = "name")
    @JsonProperty("name")
    @ApiModelProperty("名称")
    private String name;

    /**
     * 名称
     */
    @JSONField(name = "title")
    @JsonProperty("title")
    @ApiModelProperty("名称")
    private String title;

    /**
     * 系统
     */
    @JSONField(name = "systemId")
    @JsonProperty("systemId")
    @ApiModelProperty("系统")
    private String systemId;

    /**
     * 包名
     */
    @JSONField(name = "packageName")
    @JsonProperty("packageName")
    @ApiModelProperty("包名")
    private String packageName;

    /**
     * 描述
     */
    @JSONField(name = "description")
    @JsonProperty("description")
    @ApiModelProperty("描述")
    private String description;

    /**
     * 定义
     */
    @JSONField(name = "schema")
    @JsonProperty("schema")
    @ApiModelProperty("定义")
    private PojoSchema schema;

    /**
     * 模型
     */
    @JSONField(name = "model")
    @JsonProperty("model")
    @ApiModelProperty("模型")
    private String model;

    public void setSchema(PojoSchema schema) {

        if(schema!=null)
        {
            if(StringUtils.isEmpty(schema.getId()))
                schema.setId(schema.getSystem()+".domain."+schema.getName());
            this.setId(schema.getId());
            if(!StringUtils.isEmpty(schema.getName()))
                this.setName(schema.getName());
            if(!StringUtils.isEmpty(schema.getSystem()))
                this.setSystemId(schema.getSystem());
            if(!StringUtils.isEmpty(schema.getTitle()))
                this.setTitle(schema.getTitle());
            if(!StringUtils.isEmpty(schema.getDescription()))
                this.setDescription(schema.getDescription());
            if(!StringUtils.isEmpty(schema.getPackage()))
                this.setPackageName(schema.getPackage());
        }
        this.schema = schema;
    }

    /**
     * 存储
     */
    @JSONField(name = "poModels")
    @JsonProperty("poModels")
    @ApiModelProperty("存储")
    private String poModels;

    public String getPoModels()
    {
        if(StringUtils.isEmpty(poModels)&&this.poSchemas!=null)
            poModels= JSON.toJSONString(poSchemas);
        return poModels;
    }

    @JSONField(serialize = false)
    @JsonIgnore
    public String getKeyPropertyName()
    {
        PojoSchema keyProperty=getKeyProperty();
        if(keyProperty!=null)
            return keyProperty.getName().toLowerCase();
        return "id";
    }

    @JSONField(serialize = false)
    @JsonIgnore
    public PojoSchema getKeyProperty()
    {
        if(!ObjectUtils.isEmpty(this.getKeyMap().values()))
            return this.getKeyMap().values().iterator().next();
        return null;
    }


    @JSONField(serialize = false)
    @JsonIgnore
    public String getKeyFieldName()
    {
        if(!ObjectUtils.isEmpty(this.getKeyMap().keySet()))
            return this.getKeyMap().keySet().iterator().next().toLowerCase();
        return "id";
    }

    @JSONField(serialize = false)
    @JsonIgnore
    public Map<String,PojoSchema> getKeyMap()
    {
        if(this.getSchema()!=null&&this.getSchema().getKeyMap()!=null)
            return this.getSchema().getKeyMap();
        return null;
    }

    public Serializable getKeyValue(BaseData data,boolean genKeyWhenNotExists)
    {
        Map<String,PojoSchema> keyMap= this.getKeyMap();
        if(keyMap!=null)
        {
            if (keyMap.size()==1)
            {
                PojoSchema keyProperty=this.getKeyProperty();
                String keyPropertyName=keyProperty.getName().toLowerCase();
                Object key=data.get(keyPropertyName);
                if(ObjectUtils.isEmpty(key))
                {
                    key=data.getKey();
                    if(!ObjectUtils.isEmpty(key))
                            data.set(keyPropertyName, key);
                }
                if(ObjectUtils.isEmpty(key))
                {
                    if(genKeyWhenNotExists)
                    {
                        if(PojoSchema.Type.integer.getCode().equals(keyProperty.getType())||PojoSchema.Type.number.getCode().equals(keyProperty.getType()))
                            key=IdWorker.getId();
                        else
                            key=IdWorker.get32UUID();
                        data.set(keyPropertyName,key);
                    }
                    else
                        return null;
                }
                return (Serializable)key;
            }
            else if(keyMap.size()>1)
            {
                String key="";
                for(PojoSchema keySchema:keyMap.values())
                {
                    if(ObjectUtils.isEmpty(data.get(keySchema.getName().toLowerCase())))
                        return null;
                    if(!StringUtils.isEmpty(key))
                        key+="||";
                    else
                        key+=data.getStringValue(keySchema.getName().toLowerCase());
                }
                return key;
            }
        }

        return null;
    }

    public BaseData newData(Object keyValue)
    {
        return setKeyValue(new BaseData(),keyValue);
    }

    public BaseData setKeyValue(BaseData data,Object keyValue)
    {
        Map<String,PojoSchema> keyMap= this.getKeyMap();
        if(keyMap!=null)
        {
            if (keyMap.size()==1)
            {
                PojoSchema keyProperty=this.getKeyProperty();
                data.set(keyProperty.getName().toLowerCase(),keyValue);
                return data;
            }
            else if(keyMap.size()>1)
            {
                String key=DataObject.getStringValue(keyValue,"");
                String[] keys=key.split("\\|\\|");
                if(keyMap.size()!=keys.length)
                    return null;
                int i=0;
                for(PojoSchema keySchema:keyMap.values())
                {
                    if(PojoSchema.Type.integer.getCode().equals(keySchema.getType()))
                        data.set(keySchema.getName().toLowerCase(),DataObject.getLongValue(keys[i],null));
                    else if(PojoSchema.Type.number.getCode().equals(keySchema.getType()))
                        data.set(keySchema.getName().toLowerCase(),DataObject.getBigDecimalValue(keys[i],null));
                    else if(PojoSchema.Type.string.getCode().equals(keySchema.getType())&&(!StringUtils.isEmpty(keySchema.getFormat()))&&keySchema.getFormat().indexOf("data")==0)
                        data.set(keySchema.getName().toLowerCase(),DataObject.getTimestampValue(keys[i],null));
                    else
                        data.set(keySchema.getName().toLowerCase(),keys[i]);
                }
                return data;
            }
        }

        return null;
    }



	@JSONField(serialize = false)
	@JsonIgnore
	public String getDefaultDataSource()
	{
		return getSchema()!=null?getSchema().getDefaultDataSoruce():"";
	}


    @JSONField(serialize = false)
    @JsonIgnore
	private Map<String,POSchema> poSchemas;

    @JSONField(serialize = false)
    @JsonIgnore
    public POSchema getDefaultPOSchema()
    {
        return getPOSchema("default");
    }
    public DOModel addPOSchema(String name,POSchema poSchema)
    {
        if(poSchema!=null)
        {
            if(poSchemas==null)
                poSchemas=new LinkedHashMap<>();
            poSchemas.put(name,poSchema.build());
        }

        return this;
    }
	public POSchema getPOSchema(String name)
    {

        if(StringUtils.isEmpty(name)&&this.getSchema()!=null&&(!StringUtils.isEmpty(this.getSchema().getDefaultDataSoruce())))
            name=this.getSchema().getDefaultDataSoruce();
        if(StringUtils.isEmpty(name))
            name="mysql";

        if(poSchemas==null)
            poSchemas=new LinkedHashMap<>();
        if(poSchemas.containsKey(name))
        {
            return poSchemas.get(name);
        }
        String vendorProvider=POSchema.provider.get(name);
        if((!StringUtils.isEmpty(vendorProvider))&&(!name.equals(vendorProvider))&&poSchemas.containsKey(vendorProvider))
            return poSchemas.get(vendorProvider);


        if(this.getSchema()!=null&&("default".equals(name)||this.getSchema().getDefaultDataSoruce().equalsIgnoreCase(name)))
        {
            POSchema defaultPOSchema= TransUtils.PojoSchema2PO(this.getSchema());
            if(defaultPOSchema!=null) {
                poSchemas.put("default", defaultPOSchema);
                if(!StringUtils.isEmpty(this.getSchema().getDefaultDataSoruce()))
                    poSchemas.put(this.getSchema().getDefaultDataSoruce().toLowerCase(),defaultPOSchema);
                return defaultPOSchema;
            }
        }
        return null;
    }

}


