package com.boman.web.core.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.boman.common.core.utils.DateUtils;
import com.boman.common.core.utils.SecurityUtils;
import com.boman.common.core.utils.collection.CollectionUtils;
import com.boman.common.core.utils.obj.ObjectUtils;
import com.boman.common.core.web.domain.AjaxResult;
import com.boman.common.redis.RedisKey;
import com.boman.common.redis.service.RedisService;
import com.boman.domain.SysDictData;
import com.boman.gen.api.RemoteGenTableColumnService;
import com.boman.gen.api.RemoteGenTableService;
import com.boman.gen.controller.MyController;
import com.boman.gen.domain.GenTable;
import com.boman.gen.domain.GenTableColumn;
import com.boman.gen.domain.GenTableRelation;
import com.boman.system.api.RemoteDictDataService;
import com.boman.web.core.constant.FormDataConstant;
import com.boman.web.core.constant.MaskConstant;
import com.boman.web.core.constant.SubmitConstant;
import com.boman.web.core.domain.*;
import com.boman.web.core.service.delete.IBaseDeleteService;
import com.boman.web.core.service.save.IBaseSaveService;
import com.boman.web.core.service.select.IBaseSelectService;
import com.boman.web.core.service.submit.IBaseSubmitService;
import com.boman.web.core.service.update.IBaseUpdateService;
import com.boman.web.core.utils.ColumnUtils;
import com.boman.web.core.utils.IdUtils;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.sql.Timestamp;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static com.boman.common.core.utils.obj.ObjectUtils.*;
import static com.boman.web.core.constant.FormDataConstant.*;
import static com.boman.web.core.utils.ColumnUtils.*;

/**
 * @author shiqian
 * @description
 * @date 2021年03月22日 09:51
 **/
@Component
public class TableServiceCmdService {

    @Resource
    private IBaseDeleteService deleteService;
    @Resource
    private IBaseSaveService saveService;
    @Resource
    private RedisService redisService;
    @Resource
    private IBaseSelectService selectService;
    @Resource
    private IBaseSubmitService submitService;
    @Resource
    private IBaseUpdateService updateService;
    @Resource
    private  RestTemplate restTemplate;
    @Resource
    private RemoteDictDataService remoteDictDataService;
    @Resource
    private RemoteGenTableService remoteGenTableService;
    @Resource
    private RemoteGenTableColumnService remoteGenTableColumnService;

    private static final Logger LOGGER = LoggerFactory.getLogger(TableServiceCmdService.class);

//    private BaseTableDTO packTableDTO(BaseTableSaveDTO baseTableSaveDTO) {
//        BaseTableDTO baseTableDTO = new BaseTableDTO();
//        baseTableDTO.setFixedData(baseTableSaveDTO.getFixedData());
//        baseTableDTO.setObjId(baseTableSaveDTO.getObjId());
//        baseTableDTO.setTable(baseTableSaveDTO.getTable());
//        return baseTableDTO;
//    }

//    public final AjaxResult objectSave(BaseTableSaveDTO baseTableSaveDTO) {
//        AjaxResult result = AjaxResult.success();
//        BaseTableDTO baseTableDTO = packTableDTO(baseTableSaveDTO);
//        TableServiceContext context = TableServiceContext.createFrom(baseTableDTO);
//        // 拿到pkName和maxId
//        List<GenTableColumn> columns = context.getTable().getColumns();
//        String pkName = IdUtils.getPkName(columns);
//        requireNonNull(pkName, "主键名称为空");
//
//        // 新增
//        if (ObjectUtils.ltZero(baseTableDTO.getObjId())) {
//            Long maxId = IdUtils.getMaxId(baseTableDTO.getTable(), pkName);
//            RowResult rowResult = saveService.insertRow(context.getRealTableName(), pkName, maxId, context.getRows().get(0), columns);
//            if (RowResult.checkSuccess(rowResult)) {
//                LOGGER.info("保存成功，封装到数据库的数据为: {}", JSON.toJSONString(rowResult.getData()));
//            } else {
//                LOGGER.error("保存失败，保持的原始数据为: {}", JSON.toJSONString(baseTableSaveDTO));
//                result = AjaxResult.error();
//            }
//        }else {
//            JSONObject commitData = context.getRows().get(0).getCommitData();
//
//            // 编辑
//            int effective = updateService.updateByIdList(context, pkName
//                    , Collections.singletonList(baseTableDTO.getObjId()), commitData);
//            if (effective > 0) {
//                LOGGER.info("修改成功，封装到数据库的数据为: {}", JSON.toJSONString(context.getRows().get(0).getCommitData()));
//            } else {
//                LOGGER.error("修改失败，前台传来的原始数据为: {}", JSON.toJSONString(context.getRows().get(0).getCommitData()));
//                result = AjaxResult.error();
//            }
//        }
//
//        return result;
//
//    }

    public final AjaxResult objectSave(BaseTableSaveDTO dto) {
        AjaxResult result = AjaxResult.success();

        TableContext context = TableContext.createContext(dto);
        // 拿到pkName和maxId
        String pkName = context.getPkName();
        JSONObject commitData = context.getCommitData();

        // 新增
        if (ActionType.INSERT.equals(context.getActionType())) {
            Long maxId = IdUtils.getMaxId(dto.getTable(), pkName);
            RowResult rowResult = saveService.insertRow(context, maxId);
            if (RowResult.checkSuccess(rowResult)) {
                LOGGER.info("保存成功，封装到数据库的数据为: {}", JSON.toJSONString(rowResult.getData()));
            } else {
                LOGGER.error("保存失败，保持的原始数据为: {}", JSON.toJSONString(dto));
                result = AjaxResult.error();
            }
        } else {
            // 编辑
            int effective = updateService.updateByIdList(context, Collections.singletonList(context.getId()));
            if (effective > 0) {
                LOGGER.info("修改成功，封装到数据库的数据为: {}", JSON.toJSONString(commitData));
            } else {
                LOGGER.error("修改失败，前台传来的原始数据为: {}", JSON.toJSONString(commitData));
                result = AjaxResult.error();
            }
        }

        return result;

    }

    /**
     * 功能描述: 通用删除接口 (真的删除)
     *
     * @param dto 前台传过来的dto
     * @return com.boman.common.core.web.domain.AjaxResult
     */
    public AjaxResult objectDelete(BaseTableSaveDTO dto) {
        requireNonNull(dto.getTable());
        Long[] idArr = CollectionUtils.listToArray(dto.getIdList());
        requireNonNull(idArr);
        // 拿到pkName
        GenTable genTable = getTableFromRedisByTableName(RedisKey.TABLE_INFO, dto.getTable());
        String pkName = IdUtils.getPkName(genTable.getColumns());

        List<RowResult> result = Lists.newArrayListWithCapacity(idArr.length);
        for (Long id : idArr) {
            RowResult rowResult = deleteService.deleteById(dto.getTable(), pkName, id);
            result.add(rowResult);
            LOGGER.info(rowResult.getMessage() + ", id: {}", id);
        }

        // RowResult rowResult = deleteService.objectDelete(idArr, dto.getTable(), requireNonNull(pkName, "主键名称为空"));

        return AjaxResult.success(result);
    }


    /**
     * 功能描述: 通用删除接口 (真的删除)
     *
     * @param dto 前台传过来的dto
     * @return com.boman.common.core.web.domain.AjaxResult
     */
    public AjaxResult objectLogicDelete(BaseTableSaveDTO dto) {
        requireNonNull(dto.getTable());
        Long[] idArr = CollectionUtils.listToArray(dto.getIdList());
        requireNonNull(idArr);

        // 拿到pkName
        GenTable genTable = getTableFromRedisByTableName(RedisKey.TABLE_INFO, dto.getTable());
        String pkName = IdUtils.getPkName(genTable.getColumns());

        List<RowResult> result = Lists.newArrayListWithCapacity(idArr.length);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(dto.getLogicDelName(), dto.getLogicDelValue());
        for (Long id : idArr) {
            RowResult rowResult = deleteService.objectLogicDelete(new Long[]{id}, dto.getTable(), pkName, jsonObject);
            result.add(rowResult);
            LOGGER.info(rowResult.getMessage() + ", id: {}", id);
        }

        return AjaxResult.success(result);
    }

    /**
     * 功能描述: 获取单表单数据
     *
     * @param dto condition
     * @return com.boman.common.core.web.domain.AjaxResult
     */
    public AjaxResult queryList(BaseTableSaveDTO dto) {
        requireNonNull(dto.getTable());

        // 拿到每个字段对应的查询类型，=、 like、 >、 <
        GenTable genTable = getTableFromRedisByTableName(RedisKey.TABLE_INFO, dto.getTable());
        JSONObject fixedData = dto.getFixedData();
        fixedData = ifNullSetEmpty(fixedData);

        // 查询条件
        JSONObject condition = ifNullSetEmpty(fixedData.getJSONObject(CONDITION));
        List<GenTableColumn> columns = genTable.getColumns();
        // 封装好以后的查询条件
        JSONObject packCondition = ifNullSetEmpty(packColCondition(columns, condition));
        // 需要返回到前台的列, 需要判断是否是列表展示, 4为判断列表是否可见
        JSONArray showData = filterData(columns, 4, fixedData.getJSONArray(SHOW_DATA), MaskConstant.LIST_VISIBLE::equals);

        JSONObject rows = new JSONObject();
        int total = selectService.countByCondition(genTable.getTableName(), condition, packCondition);
        rows.put(FormDataConstant.PAGE_TOTAL, total);
        if (total <= 0) {
            rows.put(FormDataConstant.PAGE_ROWS, null);
            return AjaxResult.success(rows);
        }

        List<JSONObject> result = selectService.selectByCondition(genTable.getTableName(), condition, packCondition
                , showData, dto.getOrderBy(), dto.getLimit(), dto.getOffset());
        // 处理时间
        handlerDate(result, columns);
        // 处理字典值
        handlerSysDictData(result, columns);
        // 处理外键
        handlerForeignKey(result, columns);
        // 定制接口
        result = isCustomized(dto.getTable(),result,"trigger_retrieve");

        rows.put(FormDataConstant.PAGE_ROWS, result);
        return AjaxResult.success(rows);
    }

    private void handlerForeignKey(List<JSONObject> result, List<GenTableColumn> columns) {
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(result)) {
            return;
        }

        // 拿到所有有fk的列
        columns = filter(columns, col -> ObjectUtils.isNotEmpty(col.getForeignKey()));
        for (GenTableColumn column : columns) {
            JSONObject jsonObject = new JSONObject();
//            Long selfTableId = column.getTableId();
            String selfColumnName = column.getColumnName();
            for (JSONObject json : result) {
                if (json.containsKey(selfColumnName)) {
                    Object value = json.get(selfColumnName);

                    Long fkColumnId = Long.parseLong(column.getForeignKey());
                    GenTableColumn fkTableColumn = remoteGenTableColumnService.getById(fkColumnId);
                    Long fkTableId = fkTableColumn.getTableId();
                    GenTable fkGenTable = remoteGenTableService.getByTableId(fkTableId);
                    String fkTableName= fkGenTable.getTableName();

                    // select * from fkTableName where fkTableColumn.columnName = value;

//                    jsonObject.put(columnName, "");
//                    jsonObject.put("columnName", "");

                }
            }


        }
    }

    /**
     * 功能描述: 把timeStamp转为string
     *
     * @param result 被转的数据
     */
    private void handlerDate(List<JSONObject> result, List<GenTableColumn> columns) {
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(result)) {
            return;
        }

        for (JSONObject jsonObject : result) {
            for (GenTableColumn column : columns) {
                if (jsonObject.containsKey(column.getColumnName()) && DATETIME.equalsIgnoreCase(column.getColumnType())) {
                    getStrByTimeStamp(jsonObject, column.getColumnName());
                }
            }
        }
    }

    /**
     * 功能描述: 把返回值中含有字典值的转为可视化的心事
     *
     * @param result 被转的数据
     */
    private void handlerSysDictData(List<JSONObject> result, List<GenTableColumn> columns) {
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(result)) {
            return;
        }

        for (JSONObject jsonObject : result) {
            for (GenTableColumn column : columns) {
                String dictType = column.getDictType();
                if (isNotEmpty(dictType) && jsonObject.containsKey(column.getColumnName())) {
                    String dictLabel = remoteDictDataService.selectDictLabel(dictType, jsonObject.getString(column.getColumnName()));
                    jsonObject.put(column.getColumnName(), dictLabel);
                }
            }
        }
    }

    /**
     * 功能描述: 把jsonObject中时间类型转为string，再放到jsonObject中，类型为: yyyy-mm-dd
     *
     * @param jsonObject jsonObject
     * @param columnType create_time update_time...
     */
    private void getStrByTimeStamp(JSONObject jsonObject, String columnType) {
        Date date = jsonObject.getTimestamp(columnType);
        if (null != date) {
            jsonObject.put(columnType, DateUtils.dateTime(date));
        }
    }


    /**
     * 功能描述: 获取单表单数据
     *
     * @param dto condition
     * @return com.boman.common.core.web.domain.AjaxResult
     */
    public AjaxResult getObject(BaseTableSaveDTO dto) {
        requireNonNull(dto.getTable());

        // 拿到每个字段对应的查询类型，=、 like、 >、 <
        // 拿到pkName
        GenTable genTable = getTableFromRedisByTableName(RedisKey.TABLE_INFO, dto.getTable());
        String pkName = IdUtils.getPkName(genTable.getColumns());

        JSONObject fixedData = dto.getFixedData();
        fixedData = ifNullSetEmpty(fixedData);
        Long id = fixedData.getLong(FormDataConstant.ID);
        requireNonNull(id);
        List<GenTableColumn> columns = genTable.getColumns();
        // 默认查所有字段，不支持自定义
        JSONObject jsonObject = selectService.selectById(genTable.getTableName(), pkName, id);
        // name=username, value=zhangsan, type=input, types=[{},{}]
        handlerDate(Collections.singletonList(jsonObject), columns);
        List<JSONObject> result = packSingleObj(jsonObject, columns);
        return AjaxResult.success(result);
    }

    /**
     * 功能描述: 单对象查询，封装成此类型返给前台：name=username, value=zhangsan, type=input, types=[{},{}]
     *
     * @param jsonObject 数据库查出的字段名称对应字段值
     * @param columns    该表对应的所有的字段的信息
     * @return java.util.List<com.alibaba.fastjson.JSONObject>
     */
    private List<JSONObject> packSingleObj(JSONObject jsonObject, List<GenTableColumn> columns) {
        if (MapUtils.isEmpty(jsonObject)) {
            return Collections.emptyList();
        }

        List<JSONObject> result = Lists.newArrayListWithCapacity(jsonObject.size());
        for (GenTableColumn column : columns) {
            JSONObject map = new JSONObject();
            for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
                if (column.getColumnName().equalsIgnoreCase(entry.getKey())) {
                    map.put(SINGLE_OBJ_NAME, column.getColumnName());
                    map.put(SINGLE_OBJ_VALUE, entry.getValue());
                    String htmlType = column.getHtmlType();
                    map.put(SINGLE_OBJ_TYPE, htmlType);
                    if (NEED_QUERY_DICT_LIST.contains(htmlType)) {
                        map.put(SINGLE_OBJ_TYPES, remoteDictDataService.listByType(column.getDictType()));
                    }

                    result.add(map);
                }
            }
        }

        return result;
    }

    /**
     * 功能描述: 封装成查询条件 key: 列名，  value：查询条件_查询类别
     * eg: [{"config_name": ["系统配置", "EQ", "varchar(100)"]}]
     *
     * @param columns columns
     * @return com.alibaba.fastjson.JSONObject
     */
    private JSONObject packColCondition(List<GenTableColumn> columns, JSONObject condition) {
        requireNonNull(columns);

        JSONObject result = new JSONObject(columns.size());
        for (Map.Entry<String, Object> entry : condition.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            for (GenTableColumn column : columns) {
                // long string collection 暂时只作此三种类型判断
                if (column.getColumnName().equalsIgnoreCase(key) && ObjectUtils.isNotEmpty(value)) {
                    // columnType 作为判断需不需要转义的一个标准，防止索引失效
                    result.put(key, Lists.newArrayList(String.valueOf(value), column.getQueryType(), column.getColumnType()));
                    break;
                }
            }
        }

        return result;
    }

    /**
     * 功能描述: 获取表单查询字段、按钮、表头
     * 注意: 都是从redis中拿的，如果数据库和redis不一致，则需刷新一下redis
     * 刷新的入口为 {@link MyController#loadTable(GenTable)}
     * <p>
     * eg:{
     * "table": "sys_config",
     * }
     *
     * @param condition condition
     * @return com.boman.common.core.web.domain.AjaxResult
     */
    public AjaxResult getTableQuery(BaseTableSaveDTO condition) {
        GenTable genTable = getTableFromRedisByTableName(RedisKey.TABLE_INFO, condition.getTable());
        List<GenTableColumn> columns = genTable.getColumns();
        JSONObject jsonObject = new JSONObject();
        // 查询字段
        ArrayList<GenTableColumn> queryList = Lists.newArrayListWithCapacity(16);
        for (GenTableColumn column : columns) {
            if (GenTableColumn.IS_QUERY.equalsIgnoreCase(column.getIsQuery())) {
                String dictType = column.getDictType();
                if (ObjectUtils.isNotEmpty(dictType)) {
                    List<SysDictData> sysDictData1 = remoteDictDataService.listByType(dictType);
                    column.setSysDictData(sysDictData1);
                }

                queryList.add(column);
            }
        }

        jsonObject.put(FormDataConstant.QUERY_LIST, queryList);
        // genTable.getMenuRole() 暂时数据库没有数据，
        jsonObject.put(FormDataConstant.BUTTON_LIST, Strings.nullToEmpty(genTable.getMenuRole()));

        jsonObject.put(FormDataConstant.TABLE_HEAD_LIST, getTableHeadList(genTable));
        return AjaxResult.success(jsonObject);
    }

    /**
     * 功能描述: 获取表单查询字段
     * 注意: 都是从redis中拿的，如果数据库和redis不一致，则需刷新一下redis
     * 刷新的入口为 {@link MyController#loadTable(com.boman.gen.domain.GenTable)}
     *
     *                    eg:{
     *                          "table": "sys_config"
     *                        }
     *
     * @param condition condition
     * @return com.boman.common.core.web.domain.AjaxResult
     */
    public AjaxResult getQueryParam(BaseTableSaveDTO condition) {
        GenTable genTable = getTableFromRedisByTableName(RedisKey.TABLE_INFO, condition.getTable());
        List<GenTableColumn> columns = genTable.getColumns();
        // 查询字段
        ArrayList<GenTableColumn> queryList = Lists.newArrayListWithCapacity(16);
        for (GenTableColumn column : columns) {
            if (GenTableColumn.IS_QUERY.equalsIgnoreCase(column.getIsQuery())) {
                String dictType = column.getDictType();
                if (ObjectUtils.isNotEmpty(dictType)) {
                    List<SysDictData> sysDictData1 = remoteDictDataService.listByType(dictType);
                    column.setSysDictData(sysDictData1);
                }
                queryList.add(column);
            }
        }

        return AjaxResult.success(queryList);
    }

    /**
     * 功能描述: 获取表单表头
     * 注意: 都是从redis中拿的，如果数据库和redis不一致，则需刷新一下redis
     * 刷新的入口为 {@link MyController#loadTable(com.boman.gen.domain.GenTable)}
     *
     *                    eg:{
     *                          "table": "sys_config"
     *                        }
     *
     * @param condition condition
     * @return com.boman.common.core.web.domain.AjaxResult
     */
    public AjaxResult getTableHead(BaseTableSaveDTO condition) {
        GenTable genTable = getTableFromRedisByTableName(RedisKey.TABLE_INFO, condition.getTable());
        return AjaxResult.success(getTableHeadList(genTable));
    }

    /**
     * 功能描述: 获取表单按钮
     * 注意: 都是从redis中拿的，如果数据库和redis不一致，则需刷新一下redis
     * 刷新的入口为 {@link MyController#loadTable(com.boman.gen.domain.GenTable)}
     *
     *                    eg:{
     *                          "table": "sys_config"
     *                        }
     *
     * @param condition condition
     * @return com.boman.common.core.web.domain.AjaxResult
     */
    public AjaxResult getButton(BaseTableSaveDTO condition) {
        GenTable genTable = getTableFromRedisByTableName(RedisKey.TABLE_INFO, condition.getTable());
        return AjaxResult.success("成功", Strings.nullToEmpty(genTable.getMenuRole()));
    }


    /**
     * 根据表对象获取要显示的表头信息
     * @param genTable
     * @return
     */
    public List<GenTableColumn> getTableHeadList(GenTable genTable){
        List<GenTableColumn> columns = genTable.getColumns();
        // 表头
        return filterData(columns, 4, MaskConstant.LIST_VISIBLE::equals);
    }

    /**
     * 功能描述: 获取表单子表
     *
     * @param condition condition
     * @return com.boman.common.core.web.domain.AjaxResult
     */
    public AjaxResult objectTab(BaseTableSaveDTO condition) {
        //获取到主表对象
        GenTable genTable = getTableFromRedisByTableName(RedisKey.RELATION, condition.getTable());
        //从主表对象的relationList中获取出所有子表表对象
        List<GenTable> childTableList = genTable.getRelationList();
        // 表头
        List<GenTableColumn> tableHeadList = getTableHeadList(genTable);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(FormDataConstant.REF, childTableList);
        jsonObject.put(FormDataConstant.TABLE_HEAD_LIST, tableHeadList);
        return AjaxResult.success(jsonObject);
    }

    public String getChildColumnNameByParentTableName(GenTable parentGenTable, Long childTableTableId){
        requireNonNull(parentGenTable.getTableName(), "主表名称为空");
//        GenTable primaryTable = redisService.getCacheObject(RedisKey.TABLE_INFO + genTable.getTableName());
        Long parentTableId = parentGenTable.getTableId();
        List<GenTableRelation> relations = redisService.getCacheObject(RedisKey.RELATION_INFO);
        relations = relations.stream()
                .filter(relation -> relation.getRelationParentId().equals(parentTableId))
                .collect(Collectors.toList());

        for (GenTableRelation relation : relations) {
            if (relation.getRelationChildId().equals(6L)) {
               // tableColumnService.selectGenTableColumnListByTableId(childTableTableId);
//                return
            }
        }


        return "";

    }

    /**
     * 功能描述: 表单提交接口
     *
     * @param condition condition
     * @param isSubmit  提交true， 反提交false
     * @return com.boman.common.core.web.domain.AjaxResult
     */
    public AjaxResult objectSubmit(BaseTableSaveDTO condition, boolean isSubmit) {
        GenTable genTable = getTableFromRedisByTableName(RedisKey.TABLE_INFO, condition.getTable());
        List<JSONObject> commitData = condition.getCommitData();
        requireNonNull(commitData, "啥都不提交, 调什么接口？？");

        String tableName = requireNonNull(genTable.getTableName());
        String pkName = IdUtils.getPkName(genTable.getColumns());

        // 先去查出之前的状态
        List<Long> idList = commitData.stream().map(jsonObject -> jsonObject.getLong(FormDataConstant.ID))
                .collect(Collectors.toList());
        JSONArray showData = new JSONArray();
        showData.add(FormDataConstant.STATUS);
        showData.add(pkName);
        List<JSONObject> beforeList = selectService.selectByIdList(tableName, pkName, idList, showData);
        requireNonNull(beforeList);

        for (JSONObject commitDatum : commitData) {
            String dbStatus = getStatusFromFormData(commitDatum, beforeList);
            // 只能是未提交的状态下，才能调用提交
            if (isSubmit) {
                // 只能是未提交的状态下，才能调用提交, 下面是不允许
                if (!SubmitConstant.NOT_SUBMIT.equals(dbStatus)) {
                    commitDatum.put(SubmitConstant.SUBMIT_RESULT, SubmitConstant.NOT_ALLOWED);
                } else {
                    handlerSubmit(tableName, pkName, commitDatum);
                }
            } else {
                // 只有在已提交的情况下才能反提交, 下面是不允许
                if (!SubmitConstant.SUBMITTED.equals(dbStatus)) {
                    commitDatum.put(SubmitConstant.SUBMIT_RESULT, SubmitConstant.NOT_ALLOWED);
                } else {
                    handlerSubmit(tableName, pkName, commitDatum);
                }
            }
        }
        return AjaxResult.success(commitData);
    }

    /**
     * 功能描述: 处理提交和反提交
     *
     * @param tableName   tableName
     * @param pkName      pkName
     * @param commitDatum 返回给前台的数据
     */
    private void handlerSubmit(String tableName, String pkName, JSONObject commitDatum) {
        commitDatum.put(FormDataConstant.CREATE_BY, SecurityUtils.getUserId());
        commitDatum.put(FormDataConstant.CREATE_TIME, new Timestamp(System.currentTimeMillis()));
        int effective = submitService.handlerSubmit(tableName, pkName, commitDatum, commitDatum.getLong(FormDataConstant.ID));
        if (effective > 0) {
            commitDatum.put(SubmitConstant.SUBMIT_RESULT, SubmitConstant.SUCCESS);
        } else {
            commitDatum.put(SubmitConstant.SUBMIT_RESULT, SubmitConstant.FAIL);
        }
    }

    private String getStatusFromFormData(JSONObject next, List<JSONObject> commitData) {
        for (JSONObject jsonObject : commitData) {
            if (jsonObject.getLong(FormDataConstant.ID).equals(next.getLong(FormDataConstant.ID))) {
                return jsonObject.getString(FormDataConstant.STATUS);
            }
        }
        throw new IllegalArgumentException("不可能没有一个合适的");
    }


    /**
     * 是否定制
     * 判断是否需要转发到定制接口
     * @param tableName 表明
     * @param result 结果
     * @param action 动作
     * @return 结果
     */
    public List<JSONObject> isCustomized(String tableName, List<JSONObject> result, String action) {
        requireNonNull(tableName);
        requireNonNull(action);
        if (result != null && result.size() > 0){
            //获取到服务名称
            String triggerName = getTriggerName(tableName, action);
            if(triggerName != null){
                //组织请求 acos + RestTemplate
                return restTemplate.postForObject("http://" + triggerName, result, List.class);
            }
        }
        return result;
    }

    /**
     * 判断是什么action
     * @param tableName 表明
     * @param action 动作
     * @return
     */
    private String getTriggerName(String tableName, String action){
        GenTable genTable = getTableFromRedisByTableName(RedisKey.TABLE_INFO, tableName);
        requireNonNull(genTable);
        if (action.equals(TriggerActionConstant.ACTION_CREATE)){
            return genTable.getTriggerCreate();
        }else if (action.equals(TriggerActionConstant.ACTION_RETRIEVE)){
            return genTable.getTriggerRetrieve();
        }else if (action.equals(TriggerActionConstant.ACTION_UPDATE)){
            return genTable.getTriggerUpdate();
        }else if (action.equals(TriggerActionConstant.ACTION_DELETE)){
            return genTable.getTriggerDelete();
        }else if (action.equals(TriggerActionConstant.ACTION_SUBMIT)){
            return genTable.getTriggerSubmit();
        }
        return null;
    }

    /**
     * 功能描述: 查询表从redis中
     *
     * @param redisKeyPrefix 前缀
     * @param tableName      表名
     * @return com.boman.gen.domain.GenTable
     */
    private GenTable getTableFromRedisByTableName(String redisKeyPrefix, String tableName) {
        String key = requireNonNull(redisKeyPrefix) + requireNonNull(tableName);
        GenTable genTable = redisService.getCacheObject(key);
        if (ObjectUtils.isEmpty(genTable)) {
            genTable = remoteGenTableService.getByTableName(tableName);
            requireNonNull(genTable, "数据库中，未找到表对应的信息");
            // {@link com.boman.gen.controller.MyController.packTableAndInsertToRedis} 失效时间
            redisService.setCacheObject(key, genTable, 12L, TimeUnit.DAYS);
        }

        return genTable;
    }

    /**
     * 功能描述: 根据表名获取表信息、表字段和表字段对应的字典值
     *                {
     *                    "table": "sys_config",
     *                }
     *
     *
     * @param condition condition
     * @return com.boman.common.core.web.domain.AjaxResult
     */
    public AjaxResult getByTableName(BaseTableSaveDTO condition) {
        requireNonNull(condition.getTable(), "表名为空");
        requireNonNull(condition.getIsUi(), "根据表名获取表字段，未传 isUi 这个字段");
        GenTable genTable = getTableFromRedisByTableName(RedisKey.TABLE_INFO, condition.getTable());
        List<GenTableColumn> allColumns = genTable.getColumns();
        // 把新增可见的列过滤出来
//        List<GenTableColumn> returnData = ColumnUtils.filterNeedShowData(allColumns, 0, INSERT_VISIBLE::equals);
        // 普通的展示，不带折叠的
        if (BooleanUtils.isFalse(condition.getIsUi())) {
            packDictDataToColumns(allColumns, ObjectUtils::isNotEmpty);
            return AjaxResult.success(genTable);
        } else {
            // 带折叠的展示
            return getByTableName(allColumns);
        }
    }

    public AjaxResult getByTableName( List<GenTableColumn> allColumns) {
        List<GenTableColumn> parentColumns = filter(allColumns, col -> HR.equalsIgnoreCase(col.getHtmlType()));

        // 把孩子放入父亲的怀抱
        for (GenTableColumn hrColumn : parentColumns) {
            List<GenTableColumn> children = Lists.newArrayListWithCapacity(16);
            for (GenTableColumn column : allColumns) {
                if (hrColumn.getColumnId().equals(column.getHrParentId())) {
                    children.add(column);
                }
            }
            hrColumn.setHrChildren(children);
        }

        // 把孩子对应的字典值放进去
        for (GenTableColumn hrColumn : parentColumns) {
            packDictDataToColumns(hrColumn.getHrChildren(), ObjectUtils::isNotEmpty);
        }

        return AjaxResult.success(parentColumns);
    }

    public void packDictDataToColumns(List<GenTableColumn> columns, Predicate<String> predicate) {
        requireNonNull(columns, "columns 为空");
        for (GenTableColumn column : columns) {
            String dictType = column.getDictType();
            if (predicate.test(dictType)) {
                List<SysDictData> sysDictData1 = remoteDictDataService.listByType(dictType);
                column.setSysDictData(sysDictData1);
            }
        }
    }


    public AjaxResult listAllColumnsByTableId(GenTable table) {
        return remoteGenTableColumnService.listColumnsByTableId(table.getTableId());
    }
}

