package cn.estsh.i3plus.pojo.base.dynamic;

import cn.estsh.i3plus.pojo.base.bean.BaseBean;
import io.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @Description : 基础动态对象，包含方法、参数等
 * @Reference :
 * @Author : alwaysfrin
 * @CreateDate : 2019-01-24 15:56
 * @Modify:
 **/
public class DynamicEntity extends BaseBean implements Serializable {

    public static final Logger LOGGER = LoggerFactory.getLogger(DynamicEntity.class);

    private static final String ATTR_PREFIX = "$cglib_prop_";

    public String tableName;
    public List<String> propertyList;
    @ApiParam(value ="子集列表")
    private List<DynamicEntity> childList = new ArrayList<>();

    public DynamicEntity(){
        try {
            this.setPropertyList(new ArrayList<>());
            initDynamic();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public DynamicEntity(String tableName){
        this.tableName = tableName;
    }


    /**
     * 初始化属性，以便动态加载
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     */
    public void initDynamic() {
        Field[] fields = this.getClass().getDeclaredFields();
        for(Field f : fields) {
            String propName = f.getName().replace(ATTR_PREFIX, "");
            if (!isDefaultField(propName)) {
                // 添加到属性list中
                this.getPropertyList().add(propName);
                // 属性初始化
                setDynProperty(propName,getDynProperty(propName));
            }
        }
    }

    @Override
    public String toString() {
        String result = "{";

        Field[] fields = this.getClass().getDeclaredFields();
        for(Field f : fields) {
            String fieldName = f.getName().replace(ATTR_PREFIX, "");
            if (!isDefaultField(fieldName)) {

                result += "\"" + fieldName + "\":\"" + getDynProperty(fieldName) + "\",";
            }
        }
        if(fields.length > 0) {
            result = result.substring(0,result.length()-1);
        }

        result += "}";

        return result;
    }

    public void setDynProperty(Map<String,Object> params) {
        LOGGER.info("set Dyn Property params",params);
        LOGGER.info("set Dyn Property params",params);
        if (params != null && params.size() > 0){
            params.forEach((k,v)->{{
                LOGGER.info("set Dyn Property Key:{},Value:{}",k,v);
                setDynProperty(k,v);
            }});
        }
    }

    /**
     * 根据属性名，设置属性值
     * @param propName
     * @param val
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     */
    public void setDynProperty(String propName,Object val){
        String setMethodName = "set" + propName.substring(0,1).toUpperCase() + propName.substring(1);
//        String setMethodName = "set" + propName.toUpperCase();
        try {
            val = getValue(propName,val);
//            LOGGER.error("设置动态对象属性值 attr name:{} -> value:{} ",setMethodName,val);
            if(val != null){
                Method setMethod = this.getClass().getDeclaredMethod(setMethodName, new Class[]{val.getClass()});
                setMethod.invoke(this, val);
            }else{
                LOGGER.error("设置动态对象属性值 attr name:{} -> value:{} ",setMethodName,val);
            }
        } catch (NoSuchMethodException e) {
//            LOGGER.error("没有方法：{}",setMethodName,e);
            LOGGER.error("没有方法：{}",setMethodName);
        } catch (IllegalAccessException e) {
            LOGGER.error("入参出错：{}:{}",val,val.getClass(),e);
        } catch (InvocationTargetException e) {
            LOGGER.error("方法返回出错：{}",setMethodName,e);
        }
    }

    public Object getDynProperty(String propName){
        String setMethodName = "get" + propName.substring(0,1).toUpperCase() + propName.substring(1);
        Object result = null;
        try {
            Method getMethod = this.getClass().getDeclaredMethod(setMethodName);
            result = getMethod.invoke(this);
        } catch (NoSuchMethodException e) {
            LOGGER.error("没有方法：{}:{}",setMethodName,propName,e);
        } catch (IllegalAccessException e) {
            LOGGER.error("没有方法：{}:{}",setMethodName,propName,e);
        } catch (InvocationTargetException e) {
            LOGGER.error("方法返回出错：{}",setMethodName,e);
        }
        return getValue(propName,result);
    }

    /**
     * 获取默认值
     * @param propName
     * @param val
     * @return
     */
    public Object getValue(String propName,Object val){
        if(val == null){
            try {
                Field field = this.getClass().getDeclaredField(ATTR_PREFIX + propName);
                if (field.getType() == Integer.class) {
                    val = 0;
                } else if (field.getType() == Long.class) {
                    val = 0L;
                } else if (field.getType() == Float.class) {
                    val = 0.0f;
                } else if (field.getType() == Double.class) {
                    val = 0.0d;
                } else if (field.getType() == String.class) {
                    val = "";
                }else if (field.getType() == Character.class) {
                    val = "";
                }else if (field.getType() == Boolean.class) {
                    val = true;
                }else if (field.getType() == Byte.class) {
                    val = 0;
                }else if (field.getType() == Date.class) {
                    val = new Date();
                }else {
                    val = "";
                }
            }catch (NoSuchFieldException e){
                LOGGER.error("没有指定属性：{}:{}",propName,e);
            }catch (SecurityException e){
                LOGGER.error("获取属性安全错误：{}",propName,e);
            }
        }
        return val;
    }

    /**
     * 是否是本类属性
     * @param fieldName
     * @return
     */
    public boolean isDefaultField(String fieldName){
        if (!ATTR_PREFIX.equals(fieldName)) {
            if("propertyList".equals(fieldName) || "dynProperty".equals(fieldName) || "childList".equals(fieldName)
                    || "LOGGER".equals(fieldName) || "ATTR_PREFIX".equals(fieldName)){
                return true;
            }
        }
        return false;
    }


    public String getTableName() {
        return tableName;
    }

    public void setTableName(String tableName) {
        this.tableName = tableName;
    }

    public List<String> getPropertyList() {
        return propertyList;
    }

    public void setPropertyList(List<String> propertyList) {
        this.propertyList = propertyList;
    }

    public List<DynamicEntity> getChildList() {
        return childList;
    }

    public void setChildList(List<DynamicEntity> childList) {
        this.childList = childList;
    }
}
