package com.bohuikeji.frame.module.admin.base;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.bohuikeji.frame.module.admin.annotation.TableKeyField;
import com.bohuikeji.frame.module.admin.annotation.TableQueryField;
import com.bohuikeji.frame.module.admin.entity.vo.AddressVo;
import com.bohuikeji.frame.module.admin.entity.web.block.AddressBlock;
import com.bohuikeji.frame.module.admin.entity.web.block.SelectBlock;
import com.bohuikeji.frame.module.admin.enums.ColumnTypeEnum;
import com.bohuikeji.frame.module.admin.annotation.TableShowField;
import com.bohuikeji.frame.module.admin.annotation.TableNewField;
import com.bohuikeji.frame.module.admin.comparator.FieldComparator;
import com.bohuikeji.frame.module.admin.entity.web.TableColumn;
import com.bohuikeji.frame.module.admin.entity.web.TableModel;
import com.bohuikeji.frame.module.admin.entity.web.TableSearsh;
import com.bohuikeji.frame.module.admin.entity.web.block.DateBlock;
import com.bohuikeji.frame.module.admin.exception.WebVerifiedException;
import com.bohuikeji.frame.module.admin.utils.JsonUtil;
import com.bohuikeji.frame.module.admin.utils.ReflectUtil;
import com.bohuikeji.frame.module.admin.utils.StringUtils;
import io.swagger.annotations.ApiModelProperty;
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.time.temporal.Temporal;
import java.util.ArrayList;
import java.util.List;

/**
 * 实体对象父类
 * @author 10552
 *
 * @param <T>
 */
public abstract class EntityBase<T extends EntityBase<T>> extends Model<T> implements Serializable{
    protected transient Logger log = LoggerFactory.getLogger(this.getClass());

    @ApiModelProperty(value = "公用id")
    @TableField(exist = false)
    @TableShowField(value = "表格ID", show = false)
    protected Serializable id;

    public Serializable getId() {
        return pkVal();
    }

    public EntityBase<T> setId(Serializable id) {
        this.id = id;
        return this;
    }

    /**
     * 【自定义查询】查询单个字段
     *
     * @param queryWrapper
     * @return
     */
    public List<Object> selectJobs(QueryWrapper queryWrapper) {
        StringBuilder sql = new StringBuilder();
        sql.append("SELECT ");
        sql.append(queryWrapper.getSqlSelect());
        sql.append(" FROM ");
        sql.append(forDbTableName());
        sql.append(" ");
        sql.append(queryWrapper.getCustomSqlSegment());
        return sql().selectObjs(sql.toString());
    }

    /**
     * 转换Json对象
     *
     * @return
     */
    public JSONObject toJsonObj() {
        return JsonUtil.objToJson(this);
    }

    /**
     * 重写toString方法，返回实体json格式文本
     *
     * @return jsonStr
     */
    @Override
    public String toString() {
        return JSON.toJSONString(this);
    }


    /**
     * 获取Table表头
     *
     * @return
     */
    public List<String> forTableHeads() {
        List<Field> fields = ReflectUtil.getFieldsByAnnotation(this.getClass(),TableShowField.class);
        List<String> heads = new ArrayList<>(fields.size());
        for (Field field : fields) {
            field.setAccessible(true);
            TableShowField tableShowField = field.getAnnotation(TableShowField.class);
            if (tableShowField != null) {
                heads.add(tableShowField.value());
            }
        }
        return heads;
    }

    /**
     * 获取表头的Model实体及其配置结构
     *
     * @return
     */
    public List<String> forTableHeadAndConfig() {
        List<TableColumn> columns =forTableColumn();
        List<String> list = new ArrayList<>(columns.size());
        columns.forEach(t->{
            list.add(t.forParamStr());
        });
        return list;
    }

    /**
     * 获取表头配置
     * @return
     */
    public List<TableColumn> forTableColumn(){
        List<Field> fields = ReflectUtil.getFieldsByAnnotation(this.getClass(),TableShowField.class);
        List<TableColumn> list = new ArrayList<>(fields.size());
        for (Field field : fields) {
            TableShowField tableShowField = field.getAnnotation(TableShowField.class);
            TableKeyField tableKeyField=field.getAnnotation(TableKeyField.class);
            if (tableShowField == null) {
                continue;
            }
            if (!tableShowField.show()) {
                continue;
            }
            field.setAccessible(true);
            /**
             * 在此设置每列的样式
             */
            TableColumn column = TableColumn.getDefalut(field.getName(), tableShowField.value());
            ColumnTypeEnum columnType= tableShowField.type();
            //自动识别特殊格式
            if (columnType== ColumnTypeEnum.AUTO){
                switch (field.getType().getName()){
                    case "com.bohuikeji.frame.module.admin.entity.vo.AddressVo":
                        column.setDataFormatter("formatter_address");break;
                    case "com.bohuikeji.frame.module.admin.entity.vo.FileVo":
                        column.setDataFormatter("formatter_file");break;
                    case "java.lang.Boolean":
                        column.setDataFormatter("formatter_boolean");break;
                    default:break;
                }
                if(tableKeyField!=null){
                    if (field.getType().isArray()){
                        column.setDataFormatter("formatter_array_key");
                        column.setKey(tableKeyField.key().getName());
                    }else{
                        column.setDataFormatter("formatter_key");
                        column.setKey(tableKeyField.key().getName());
                    }
                }
            }
            else{
                column.setDataFormatter("formatter_"+columnType);
            }
            list.add(column);
        }
        return list;
    }


    /**
     * 获取表格组合查询组件列表
     * @return
     */
    public List<HtmlBlockFormBase> forTableQueryBlocks() {
        List<Field> fields = ReflectUtil.getFieldsByAnnotation(this.getClass(),TableQueryField.class);
        fields.sort(new FieldComparator());
        List<HtmlBlockFormBase> list = new ArrayList<>(fields.size());
        for (Field field : fields) {
            TableQueryField tableQueryField=field.getAnnotation(TableQueryField.class);
            //是否显示控件
            if(tableQueryField.show()){
                list.add(forBlockByClass(field,tableQueryField.block()));
            }
        }
        return list;
    }

    /**
     * 获取表格支持like搜索的列
     *
     * @return
     */
    public List<TableSearsh> foeTableSearch() {
        List<Field> fields = ReflectUtil.getFieldsByAnnotation(this.getClass(),TableQueryField.class);
        List<TableSearsh> list = new ArrayList<>(fields.size());
        for (Field field : fields) {
            TableQueryField tableQueryField = field.getAnnotation(TableQueryField.class);
            if (!tableQueryField.like()) continue;
            field.setAccessible(true);
            list.add(new TableSearsh(field.getAnnotation(TableField.class).value(), field.getAnnotation(TableShowField.class).value()));
        }
        return list;
    }

    /**
     * 返回弹出层模态框
     *
     * @return
     */
    public TableModel forTableModel() {
        List<Field> fields = ReflectUtil.getFieldsByAnnotation(this.getClass(),TableNewField.class);
        TableModel tableModel = new TableModel();
        List<HtmlBlockFormBase> blockList = new ArrayList<>(fields.size());
        List<HtmlBlockFormBase> addBloks=new ArrayList<>(fields.size());
        for (Field field : fields) {
            TableNewField newField = field.getAnnotation(TableNewField.class);
            HtmlBlockFormBase bloks=forBlockByClass(field,newField.block());
            if (bloks!=null){
                //配置表单Block块
                blockList.add(bloks);
                if(newField.add()){
                    addBloks.add(forBlockByClass(field,newField.block()));
                }
            }
        }
        tableModel.setAddBlocks(addBloks);
        tableModel.setInputBlocks(blockList);
        return tableModel;
    }

    /**
     * 获取Excel格式的表头
     *
     * @return
     */
    public List<List<String>> forExcelHeads() {
        List<Field> fields = ReflectUtil.getFieldsByAnnotation(this.getClass(),TableShowField.class);
        List<List<String>> heads = new ArrayList<>(fields.size());
        for (Field field : fields) {
            TableShowField tableShowField = field.getAnnotation(TableShowField.class);
            if (tableShowField.id() || (!tableShowField.show())) {
                continue;
            }
            List<String> head = new ArrayList<>(1);
            head.add(tableShowField.value());
            heads.add(head);
        }
        return heads;
    }

    /**
     * 获取Excel字段值集合
     *
     * @return
     */
    public List<String> forExcelFields() {
        List<Field> fields = ReflectUtil.getFieldsByAnnotation(this.getClass(),TableShowField.class);
        List<String> valueList = new ArrayList<>(fields.size());
        for (Field field : fields) {
            TableShowField tableShowField = field.getAnnotation(TableShowField.class);
            if (tableShowField.id() || (!tableShowField.show())) {
                continue;
            }
            try {
                Object cell=field.get(this);
                valueList.add( cell== null ? "" : field.get(this).toString());
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return valueList;
    }

    /**
     * 获取Id字段
     *
     * @return
     */
    public Field forIdField() {
        return ReflectUtil.getFieldsByAnnotation(this.getClass(),TableId.class).get(0);
    }

    /**
     * 获取Id列名称
     *
     * @return
     */
    public String forIdColumn() {
        return forIdField().getAnnotation(TableId.class).value();
    }


    /**
     * 获取表名称
     *
     * @return
     */
    public String forDbTableName() {
        return ReflectUtil.getTableName(this.getClass());
    }

    /**
     * 查询当前实体的字段值
     * @param name
     * @return
     */
    public Object queryValueByFieldName(String name) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        // 将属性的首字符大写，方便构造get，set方法
        name = name.substring(0,1).toUpperCase() + name.substring(1);
        // 获取方法
        Method m = this.getClass().getMethod("get" + name);
        // 调用getter方法获取属性值
        return m.invoke(this);
    }


    /**
     * 内部方法2，创建并初始化Html组件,用于新增和修改页面
     *
     * @param field
     * @return
     */
    private HtmlBlockFormBase forBlockByClass(Field field,Class<? extends HtmlBlockFormBase> blockClass) {
        /**
         * 特殊组件识别并处理，针对通用组件，且未指定类型
         */
        if (Temporal.class.isAssignableFrom(field.getType())){
            return  new DateBlock(field,this);
        }
        if(field.getType()== AddressVo.class){
            return  new AddressBlock(field,this);
        }
        /**
         * 下拉选择设置
         */
        TableNewField tableNewField=field.getAnnotation(TableNewField.class);
        if (tableNewField!=null&&tableNewField.options().length>0){
            return new SelectBlock(field,this);
        }
        /**
         * 第三次处理，创建默认组件
         */
        //默认处理，创建控件
        try {
            return blockClass.getConstructor(Field.class, EntityBase.class).newInstance(field, this);
        } catch (Exception e) {
            log.error("创建组件失败位于：[{}.{}]",field.getDeclaringClass(),field.getName(),e);
        }

        return null;
    }

    /**
     * 根据字段名获取数据库列名
     * @param fieldName
     * @return
     */
    public String forColumnByFieldName(String fieldName){
        Field field;
        try {
            field=this.getClass().getDeclaredField(fieldName);

        } catch (NoSuchFieldException e) {
            log.error("获取字段失败,无法找到：[{}.{}]",this.getClass().getName(),fieldName);
            e.printStackTrace();
            return null;
        }
        TableField tableField=field.getAnnotation(TableField.class);
        if (tableField==null){
            return StringUtils.toUnderline(fieldName);
        }
        return tableField.value();
    }

    /**
     * 根据数据库列名获取字段注释
     * @param columnName
     * @return
     */
    public String forExplainByColumn(String columnName){
        String fieldName=StringUtils.toCameCase(columnName);
        Field field;
        try {
            field=this.getClass().getDeclaredField(fieldName);

        } catch (NoSuchFieldException e) {
            log.error("获取字段失败,无法找到：[{}.{}]",this.getClass().getName(),fieldName);
            e.printStackTrace();
            return null;
        }
        TableShowField showField=field.getAnnotation(TableShowField.class);
        if (showField==null){
            log.error("【注解异常】无法获取注释，字段[{}.{}]未配置@TableShowField",this.getClass().getName(),fieldName);
            throw new WebVerifiedException("【注解异常】无法获取注释");
        }
        return showField.value();
    }
    /*public EntityBase updateByMap(Map<String,String> params){

    }*/
}
