package com.boman.web.core.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.boman.common.core.constant.GenConstants;
import com.boman.common.core.utils.DateUtils;
import com.boman.common.core.utils.SecurityUtils;
import com.boman.common.core.utils.array.ArrayUtils;
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.domain.constant.*;
import com.boman.gen.api.RemoteGenTableColumnService;
import com.boman.gen.api.RemoteGenTableService;
import com.boman.domain.GenTable;
import com.boman.domain.GenTableColumn;
import com.boman.system.api.RemoteDictDataService;
import com.boman.system.api.domain.SysFile;
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.IdUtils;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.math.NumberUtils;
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 static com.boman.common.core.utils.obj.ObjectUtils.*;
import static com.boman.domain.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);

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

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

        checkColumn(commitData, context.getColumns());
        // 必填项
        handlerRequired(commitData, context.getColumns());
        // 处理输入类型
        handlerInputType(commitData, context.getColumns());

        // 新增
        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;

    }

    private void handlerInputType(JSONObject commitData, List<GenTableColumn> columns) {
        for (Map.Entry<String, Object> entry : commitData.entrySet()) {
            Object value =entry.getValue();
            for (GenTableColumn column : columns) {
                if (entry.getKey().equals(column.getColumnName())
                        && ArrayUtils.arraysContains(GenConstants.COLUMNTYPE_NUMBER, getDbType(column.getColumnType()))) {
                    if ((value instanceof Number)) {
                        // ignore 这里的if不能删掉，因为else if有一个强转
                    } else if (!NumberUtils.isCreatable(((String) value))) {
                        throw new IllegalArgumentException(column.getColumnComment() + "只能输入数字");
                    }
                }
            }
        }
    }

    private void handlerRequired(JSONObject commitData, List<GenTableColumn> columns) {
        for (GenTableColumn column : columns) {
            if (GenTableColumn.IS_REQUIRED.equalsIgnoreCase(column.getIsRequired())) {
                Object value = commitData.get(column.getColumnName());
                if ((value instanceof String)) {
                    requireNonNull((String) value, column.getColumnComment() + " 为必填项");
                } else {
                    requireNonNull(value, column.getColumnComment() + " 为必填项");
                }
            }
        }
    }

    /**
     * 功能描述: 通用删除接口 (真的删除)
     *
     * @param dto 前台传过来的dto
     * @return com.boman.common.core.web.domain.AjaxResult
     */
    public AjaxResult objectDelete(FormDataDto dto) {
        requireNonNull(dto.getTable(), "tableName = [" + 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(FormDataDto dto) {
        requireNonNull(dto.getTable(), "tableName = [" + 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(FormDataDto dto) {
        requireNonNull(dto.getTable(), "tableName = [" + dto.getTable() + "] 此表不存在");

        GenTable genTable = getTableFromRedisByTableName(RedisKey.TABLE_INFO, dto.getTable());
        JSONObject fixedData = ifNullSetEmpty(dto.getFixedData());
        List<GenTableColumn> columns = genTable.getColumns();

        // 查询条件
        JSONObject condition = ifNullSetEmpty(fixedData.getJSONObject(CONDITION));
        // 检查列
        checkColumn(condition, columns);
        // 封装好以后的查询条件
        JSONObject packCondition = ifNullSetEmpty(packColCondition(columns, condition));
        JSONArray showData = fixedData.getJSONArray(SHOW_DATA);
        // 检查列
        checkColumn(showData, genTable.getColumns());
        // 需要返回到前台的列, 需要判断是否是列表展示, 4为判断列表是否可见
        showData = filterData(columns, 4, showData, MaskConstant.LIST_VISIBLE::equals);
        // 表的id单独处理，不管mask，都查出来返给前台
        IdUtils.putIfNotContains(showData, IdUtils.getPkName(columns));

        JSONObject rows = new JSONObject();
        int total = selectService.countByCondition(genTable.getTableName(), condition, packCondition);
        rows.put(FormDataConstant.PAGE_TOTAL, total);
        rows.put(TABLE_HEAD_LIST, getTableHeadList(genTable));
        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());
        // 处理blob
        handlerBlobWithJSONObject(genTable.getIsContainsBlob(), result);
        // 处理日期、外键、字典值
        handler(result = filter(result, ObjectUtils::isNotEmpty), columns);
        // 定制接口
        result = isCustomized(dto.getTable(), result, "trigger_retrieve");

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

    private void handler(List<JSONObject> result, List<GenTableColumn> columns) {
        // 处理时间
        handlerDate(result, columns);
        // 处理字典值
        handlerSysDictData(result, columns);
        // 处理外键
        handlerForeignKey(result, columns);
    }

    /**
     * 功能描述: 处理外键 todo 待优化
     *
     * @param result  result
     * @param columns 该表对应的所有的列
     */
    private void handlerForeignKey(List<JSONObject> result, List<GenTableColumn> columns) {
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(result)) {
            return;
        }
        // 拿到所有有fk的列
        List<GenTableColumn> fkColumns = filter(columns, col -> ObjectUtils.isNotEmpty(col.getForeignKey()));
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(fkColumns)) {
            return;
        }

        for (GenTableColumn column : fkColumns) {
            JSONObject jsonObject = new JSONObject();
            String selfColumnName = column.getColumnName();
            for (JSONObject json : result) {
                if (json.containsKey(selfColumnName.toUpperCase()) || json.containsKey(selfColumnName.toLowerCase())) {
                    Map<String, String> fkInfoMap = column.getFkInfo();
                    String fkTableName = fkInfoMap.get(FK_TABLE_NAME);
                    String fkColumnName = fkInfoMap.get(FK_COLUMN_NAME);
                    String dkColumnName = fkInfoMap.get(DK_COLUMN_NAME);
                    Object primaryTableFkValue = json.get(selfColumnName);

                    JSONObject param = new JSONObject();
                    param.put(fkColumnName, primaryTableFkValue);
                    JSONObject fkInfo = selectService.getOneByMap(fkTableName, param);

                    Object value = fkInfo.get(dkColumnName);
                    jsonObject.put(SINGLE_OBJ_NAME, primaryTableFkValue);
                    jsonObject.put(SINGLE_OBJ_VALUE, value);
                    json.put(selfColumnName.toLowerCase(), jsonObject);
                }
            }
        }
    }

    /**
     * 功能描述: 把timeStamp转为string, 默认类型为：YYYY_MM_DD
     *
     * @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()) && NEED_CONVERT_DATE_LIST.contains(column.getColumnType())) {
                    Date date = jsonObject.getTimestamp(column.getColumnName());
                    if (null != date) {
                        jsonObject.put(column.getColumnName(), DateUtils.dateTime(date));
                    }
                }
            }
        }
    }


    /**
     * 功能描述: 处理附件，把数据拿出来转换成name、url形式
     *
     * @param result 被转的数据
     */
    private void handlerAnnex(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())) {
                    String value = jsonObject.getString(column.getColumnName());
                    List<SysFile> fileList = JSON.parseObject(value, new TypeReference<List<SysFile>>() {
                    }.getType());
                    jsonObject.put(column.getColumnName(), fileList);
                }
            }
        }
    }

    /**
     * 功能描述: 把返回值中含有字典值的转为可视化的心事
     *
     * @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 = null;
                    try {
                        dictLabel = remoteDictDataService.selectDictLabel(dictType, jsonObject.getString(column.getColumnName()));
                        jsonObject.put(column.getColumnName(), dictLabel);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * 功能描述: 获取单表单数据
     *
     * @param dto condition
     * @return com.boman.common.core.web.domain.AjaxResult
     */
    public AjaxResult getObject(FormDataDto dto) {
        String tableName = requireNonNull(dto.getTable(), "tableName = [" + dto.getTable() + "] 此表不存在");
        Boolean isUi = requireNonNull(dto.getIsUi(), "未传isUi这个参数");
        Long id = dto.getFixedData().getLong(FormDataConstant.ID);
        requireNonNull(id, "如果是回显，则传参为此行记录的id， 如为新增，则传-1，传null可不行");

        GenTable genTable = getTableFromRedisByTableName(RedisKey.TABLE_INFO, tableName);
        List<GenTableColumn> columns = genTable.getColumns();
        // id = -1时，查询该表单对应的字段名称
        if (ltZero(id)) {
            return getByTableName(tableName, columns, isUi);
        }

        // 默认查所有字段，不支持自定义
        String pkName = IdUtils.getPkName(genTable.getColumns());
        JSONObject json = selectService.selectById(tableName, pkName, id);
        requireNonNull(json, "id 为[" + id + "]的数据不存在, 表名为[" + tableName + "]");
        // 处理blob
        handlerBlobWithJSONObject(genTable.getIsContainsBlob(), Collections.singletonList(json));
        List<GenTableColumn> parentColumns = filterHrAndSort(columns);

        // 处理成hr的形式
        for (GenTableColumn hrColumn : parentColumns) {
            List<GenTableColumn> children = Lists.newArrayListWithCapacity(16);
            for (GenTableColumn column : columns) {
                if (hrColumn.getColumnId().equals(column.getHrParentId())) {
                    // handler column
                    if (json.containsKey(column.getColumnName())) {
                        handlerSysDictData(Collections.singletonList(json), Collections.singletonList(column));
                        handlerDate(Collections.singletonList(json), Collections.singletonList(column));
                        handlerForeignKey(Collections.singletonList(json), Collections.singletonList(column));
                        if (GenConstants.HTML_IMAGE_UPLOAD.equalsIgnoreCase(column.getHtmlType())
                                || GenConstants.HTML_FILE_UPLOAD.equalsIgnoreCase(column.getHtmlType())) {
                            handlerAnnex(Collections.singletonList(json), Collections.singletonList(column));
                        }

                        column.setColumnValue(json.get(column.getColumnName()));
                    }

                    children.add(column);
                }
            }
            hrColumn.setHrChildren(children);
        }

        JSONObject result = new JSONObject();
        result.put(SHOW_DATA, parentColumns);
        result.put(BUTTON_LIST, getButton(tableName));
        return AjaxResult.success(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
     *
     * <p>
     * eg:{
     * "table": "sys_config",
     * }
     *
     * @param condition condition
     * @return com.boman.common.core.web.domain.AjaxResult
     */
    public AjaxResult getTableQuery(FormDataDto 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)) {
                    try {
                        column.setSysDictData(listSysDictDataByType(dictType));
                    } catch (Exception e) {
                        System.out.println("sq_dictType = " + dictType);
                        e.printStackTrace();
                    }
                }

                queryList.add(column);
            }
        }

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

        jsonObject.put(ViewConst.VIEW_TYPE, Strings.nullToEmpty(genTable.getTplCategory()));
        jsonObject.put(RULES, packRequireColumn(columns));
        return AjaxResult.success(jsonObject);
    }

    /**
     * 功能描述: 获取表单查询字段
     * 注意: 都是从redis中拿的，如果数据库和redis不一致，则需刷新一下redis
     *
     * <p>
     * eg:{
     * "table": "sys_config"
     * }
     *
     * @param condition condition
     * @return com.boman.common.core.web.domain.AjaxResult
     */
    public AjaxResult getQueryParam(FormDataDto 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)) {
                    column.setSysDictData(listSysDictDataByType(dictType));
                }
                queryList.add(column);
            }
        }

        return AjaxResult.success(queryList);
    }

    /**
     * 功能描述:  单独获取按钮
     * 注意: 都是从redis中拿的，如果数据库和redis不一致，则需刷新一下redis
     *
     * @param tableName tableName
     * @return com.boman.common.core.web.domain.AjaxResult
     */
    public String getButton(String tableName) {
        GenTable genTable = getTableFromRedisByTableName(RedisKey.TABLE_INFO, tableName);
        return 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(FormDataDto 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);
    }

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

        String tableName = requireNonNull(genTable.getTableName(), "tableName = [" + genTable.getTableName() + "] 此表不存在");
        String pkName = IdUtils.getPkName(genTable.getColumns());

        // 先去查出之前的状态
        List<Long> idList = map(commitData, jsonObject -> jsonObject.getLong(FormDataConstant.ID));

        List<JSONObject> beforeList = selectService.selectByIdList(tableName, pkName, idList, Lists.newArrayList(pkName, STATUS));
        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.domain.GenTable
     */
    public GenTable getTableFromRedisByTableName(String redisKeyPrefix, String tableName) {
        tableName = tableName.trim().toLowerCase();
        String key = requireNonNull(redisKeyPrefix) + requireNonNull(tableName);
        GenTable genTable = redisService.getCacheObject(key);
        if (ObjectUtils.isEmpty(genTable)) {
            genTable = remoteGenTableService.getByTableName(tableName);
            requireNonNull(genTable, "数据库中，未找到表对应的信息, tableName = " + tableName);
            // {@link com.boman.gen.controller.MyController.packTableAndInsertToRedis} 失效时间
            redisService.setCacheObject(key, genTable, 12L, TimeUnit.DAYS);
        }

        return genTable;
    }

    /**
     * 功能描述: 根据表名封装列的对应关系, 同时封装好字典值
     *
     * @param tableName  tableName
     * @param allColumns allColumns
     * @param isUi       带折叠true, 不带折叠false
     * @return com.boman.common.core.web.domain.AjaxResult
     */
    public AjaxResult getByTableName(String tableName, List<GenTableColumn> allColumns, Boolean isUi) {
        List<GenTableColumn> resultCols;
        List<GenTableColumn> parentColumns = filterHrAndSort(allColumns);
        // 所有新增可见的列
        allColumns = filterData(allColumns, 0, MaskConstant.INSERT_VISIBLE::equals);
        // 带折叠
        if (BooleanUtils.isTrue(isUi)) {
            // 把孩子放入父亲的怀抱
            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);
            }
            resultCols = parentColumns;
        } else {
            // 不带折叠
            packDictDataToColumns(allColumns, ObjectUtils::isNotEmpty);
            resultCols = allColumns;
        }

        JSONObject result = new JSONObject();
        result.put(BUTTON_LIST, getButton(tableName));
        result.put(SHOW_DATA, resultCols);
        result.put(RULES, packRequireColumn(allColumns));
        return AjaxResult.success(result);
    }

    private JSONObject packRequireColumn(List<GenTableColumn> allColumns) {
        JSONObject jsonObject = new JSONObject();
        String msg = "请输入正确的";
        for (GenTableColumn column : allColumns) {
            ArrayList<JSONObject> list = Lists.newArrayList();
            if (GenTableColumn.IS_REQUIRED.equals(column.getIsRequired())) {
                JSONObject inner1 = new JSONObject();
                inner1.put(TRIGGER, BLUR);
                inner1.put(MESSAGE, msg + column.getColumnComment());
                inner1.put(REQUIRED, true);
                list.add(inner1);
                if (isNotEmpty(column.getRegular())) {
                    JSONObject inner2 = new JSONObject();
                    inner2.put(PATTERN, column.getRegular());
                    inner2.put(TRIGGER, BLUR);
                    inner2.put(MESSAGE, msg + column.getColumnComment());
                    list.add(inner2);
                }

                jsonObject.put(column.getColumnName(), list);
            }
        }

        return jsonObject;
    }

    public void packDictDataToColumns(List<GenTableColumn> columns, Predicate<String> predicate) {
        if (isEmpty(columns)) {
            return;
        }
        for (GenTableColumn column : columns) {
            String dictType = column.getDictType();
            if (predicate.test(dictType)) {
                column.setSysDictData(listSysDictDataByType(dictType));
            }
        }
    }


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

    public List<SysDictData> listSysDictDataByType(String dictType) {
        List<SysDictData> sysDictData = null;
        try {
            sysDictData = remoteDictDataService.listByType(dictType);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sysDictData;
    }
}

