package com.yunzhupaas.base.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yunzhupaas.base.model.dbtable.vo.DbFieldVO;
import com.yunzhupaas.base.model.form.VisualTableModel;
import com.yunzhupaas.constant.MsgCode;
import com.yunzhupaas.database.constant.DbFieldConst;
import com.yunzhupaas.database.datatype.viewshow.constant.DtViewConst;
import com.yunzhupaas.database.model.dbfield.DbFieldModel;
import com.yunzhupaas.database.model.dbtable.DbTableFieldModel;
import com.yunzhupaas.database.model.entity.DbLinkEntity;
import com.yunzhupaas.database.source.DbBase;
import com.yunzhupaas.database.util.DataSourceUtil;
import com.yunzhupaas.exception.WorkFlowException;
import com.yunzhupaas.model.visualJson.FieLdsModel;
import com.yunzhupaas.model.visualJson.TableFields;
import com.yunzhupaas.model.visualJson.TableModel;
import com.yunzhupaas.model.visualJson.analysis.FormAllModel;
import com.yunzhupaas.model.visualJson.analysis.FormColumnTableModel;
import com.yunzhupaas.model.visualJson.analysis.FormEnum;
import com.yunzhupaas.util.JsonUtil;
import com.yunzhupaas.util.RandomUtil;
import com.yunzhupaas.util.StringUtil;
import com.yunzhupaas.util.TableFeildsEnum;
import com.yunzhupaas.util.visiual.YunzhupaasKeyConsts;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ：云筑产品开发平台组
 * @version: V3.1.0
 * @copyright 深圳市乐程软件有限公司
 * @date ：2022/3/25 9:30
 */
@Slf4j
@Component
public class VisualDevTableCre {
    @Autowired
    private ServiceBaseUtil serviceUtil;
    @Autowired
    private DataSourceUtil dataSourceUtil;

    /**
     * 表单赋值tableName
     *
     * @param jsonArray
     * @param tableModels
     */
    private void fieldsTableName(JSONArray jsonArray, List<TableModel> tableModels) {
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonObject = (JSONObject) jsonArray.get(i);
            String yunzhupaaskey = jsonObject.getJSONObject("__config__").getString("yunzhupaasKey");
            List<String> childrenListAll = new ArrayList() {
                {
                    add(FormEnum.card.getMessage());
                    add(FormEnum.row.getMessage());
                    add(FormEnum.tab.getMessage());
                    add(FormEnum.collapse.getMessage());
                    add(FormEnum.collapseItem.getMessage());
                    add(FormEnum.tabItem.getMessage());
                    add(FormEnum.tableGrid.getMessage());
                    add(FormEnum.tableGridTr.getMessage());
                    add(FormEnum.tableGridTd.getMessage());
                    add(FormEnum.STEPS.getMessage());
                    add(FormEnum.STEP_ITEM.getMessage());
                }
            };
            if (childrenListAll.contains(yunzhupaaskey) || StringUtil.isEmpty(yunzhupaaskey)) {
                JSONArray childArray = jsonObject.getJSONObject("__config__").getJSONArray("children");
                this.fieldsTableName(childArray, tableModels);
                jsonObject.getJSONObject("__config__").put("children", childArray);
            } else if (FormEnum.table.getMessage().equals(yunzhupaaskey)) {
                JSONArray childrenList = new JSONArray();
                JSONArray children = jsonObject.getJSONObject("__config__").getJSONArray("children");
                String tableModel = "";
                for (int k = 0; k < children.size(); k++) {
                    JSONObject childrenObject = (JSONObject) children.get(k);
                    this.fieldsModel(childrenObject, tableModels);
                    if (StringUtil.isEmpty(tableModel)) {
                        tableModel = childrenObject.getJSONObject("__config__").getString("relationTable");
                    }
                    childrenList.add(childrenObject);
                }
                jsonObject.getJSONObject("__config__").put("tableName", tableModel);
                jsonObject.getJSONObject("__config__").put("children", childrenList);
            } else {
                this.fieldsModel(jsonObject, tableModels);
            }
        }
    }

    /**
     * 赋值table
     *
     * @param jsonObject
     * @param tableModels
     */
    private TableModel fieldsModel(JSONObject jsonObject, List<TableModel> tableModels) {
        String vModel = jsonObject.getString("__vModel__");
        String relationField = StringUtil.isNotEmpty(jsonObject.getString("relationField"))
                ? jsonObject.getString("relationField")
                : "";
        String yunzhupaaskey = jsonObject.getJSONObject("__config__").getString("yunzhupaasKey");
        TableModel tableName = tableModels.stream().filter(t -> "1".equals(t.getTypeId())).findFirst().orElse(null);
        if (tableName != null) {
            jsonObject.getJSONObject("__config__").put("tableName", tableName.getTable());
        }
        List<TableModel> childTableAll = tableModels.stream().filter(t -> "0".equals(t.getTypeId()))
                .collect(Collectors.toList());
        TableModel childTableaa = childTableAll.stream()
                .filter(t -> t.getFields().stream().filter(k -> k.getField().equals(vModel)).count() > 0).findFirst()
                .orElse(null);
        if (childTableaa != null) {
            jsonObject.getJSONObject("__config__").put("relationTable", childTableaa.getTable());
        }
        if (FormEnum.relationFormAttr.getMessage().equals(yunzhupaaskey)
                || FormEnum.popupAttr.getMessage().equals(yunzhupaaskey)) {
            if (StringUtil.isNotEmpty(relationField)) {
                Boolean isSubTable = jsonObject.getJSONObject("__config__").getBooleanValue("isSubTable");
                String model = relationField.split("_yunzhupaasTable_")[0];
                jsonObject.put("relationField",
                        model + "_yunzhupaasTable_" + tableName.getTable() + (isSubTable ? "0" : "1"));
            }
        }
        if (YunzhupaasKeyConsts.BILLRULE.equals(yunzhupaaskey)) {
            if (StringUtil.isNotEmpty(relationField)) {
                Boolean isSubTable = jsonObject.getJSONObject("__config__").getBooleanValue("isSubTable");
                String model = relationField.split("_yunzhupaasTable_")[0];
                jsonObject.put("relationField",
                        model + "_yunzhupaasTable_" + tableName.getTable() + (isSubTable ? "0" : "1"));
            }
        }
        return childTableaa;
    }

    /**
     * 创建表
     *
     * @return
     */
    public List<TableModel> tableList(VisualTableModel visualTableModel) throws WorkFlowException {
        JSONArray jsonArray = visualTableModel.getJsonArray();
        List<FormAllModel> formAllModel = visualTableModel.getFormAllModel();
        String table = visualTableModel.getTable();
        String linkId = visualTableModel.getLinkId();
        String fullName = visualTableModel.getFullName();
        int primaryKey = visualTableModel.getPrimaryKey();
        List<TableModel> tableModelList = new LinkedList<>();
        Map<String, String> tableNameList = new HashMap<>();
        DbLinkEntity dbLink = serviceUtil.getDbLink(linkId);
        String type = dbLink != null ? dbLink.getDbType() : dataSourceUtil.getDbType();
        boolean isUpperCase = (DbBase.DM.equals(type) || DbBase.ORACLE.equals(type));
        boolean isLowerCase = (DbBase.POSTGRE_SQL.equals(type) || DbBase.KINGBASE_ES.equals(type));
        table = tableName(table, isUpperCase, isLowerCase);

        String relationField = tableName(TableFeildsEnum.FID.getField(), isUpperCase, isLowerCase);
        String tableField = tableName(TableFeildsEnum.FOREIGN.getField(), isUpperCase, isLowerCase);
        try {
            List<DbFieldModel> fieldList = new ArrayList<>();
            Map<String, List<DbFieldModel>> tableListAll = new HashMap<>();
            for (FormAllModel model : formAllModel) {
                if (FormEnum.mast.getMessage().equals(model.getYunzhupaasKey())) {
                    FieLdsModel fieLdsModel = model.getFormColumnModel().getFieLdsModel();
                    this.fieldList(fieLdsModel, table, fieldList);
                } else if (FormEnum.table.getMessage().equals(model.getYunzhupaasKey())) {
                    String tableName = "ct" + RandomUtil.uuId();
                    FormColumnTableModel fieLdsModel = model.getChildList();
                    List<DbFieldModel> tableList = new ArrayList<>();
                    String tableModel = fieLdsModel.getTableModel();
                    List<FieLdsModel> fieldsList = fieLdsModel.getChildList().stream().map(t -> t.getFieLdsModel())
                            .collect(Collectors.toList());
                    for (FieLdsModel tableFieLdsModel : fieldsList) {
                        this.fieldList(tableFieLdsModel, tableName, tableList);
                    }
                    this.dbTableField(tableList, true, primaryKey, isLowerCase, tableField, relationField);
                    tableNameList.put(tableModel, tableName);
                    tableListAll.put(tableModel, tableList);
                }
            }

            this.dbTableField(fieldList, false, primaryKey, isLowerCase, tableField, relationField);
            fieldList.add(ConcurrencyUtils.getDbFieldModel(TableFeildsEnum.TENANTID, isUpperCase, isLowerCase));
            fieldList.add(ConcurrencyUtils.getDbFieldModel(TableFeildsEnum.FLOWID, isUpperCase, isLowerCase));
            fieldList.add(ConcurrencyUtils.getDbFieldModel(TableFeildsEnum.VERSION, isUpperCase, isLowerCase));
            fieldList.add(ConcurrencyUtils.getDbFieldModel(TableFeildsEnum.FLOWTASKID, isUpperCase, isLowerCase));
            if (visualTableModel.getLogicalDelete()) {// 删除标志字段
                fieldList.add(ConcurrencyUtils.getDbFieldModel(TableFeildsEnum.DELETEMARK, isUpperCase, isLowerCase));
                fieldList.add(ConcurrencyUtils.getDbFieldModel(TableFeildsEnum.DELETETIME, isUpperCase, isLowerCase));
                fieldList.add(ConcurrencyUtils.getDbFieldModel(TableFeildsEnum.DELETEUSERID, isUpperCase, isLowerCase));
            }
            List<DbTableFieldModel> dbTableList = new ArrayList<>();
            // 创建子表
            for (String key : tableListAll.keySet()) {
                String tableName = tableName(tableNameList.get(key), isUpperCase, isLowerCase);
                List<DbFieldModel> datableList = tableListAll.get(key);
                datableList.add(ConcurrencyUtils.getDbFieldModel(TableFeildsEnum.TENANTID, isUpperCase, isLowerCase));
                if (visualTableModel.getLogicalDelete()) {// 删除标志字段
                    datableList.add(
                            ConcurrencyUtils.getDbFieldModel(TableFeildsEnum.DELETEMARK, isUpperCase, isLowerCase));
                    datableList.add(
                            ConcurrencyUtils.getDbFieldModel(TableFeildsEnum.DELETETIME, isUpperCase, isLowerCase));
                    datableList.add(
                            ConcurrencyUtils.getDbFieldModel(TableFeildsEnum.DELETEUSERID, isUpperCase, isLowerCase));
                }
                DbTableFieldModel dbTable = this.dbTable(linkId, tableName, datableList, true, fullName);
                dbTableList.add(dbTable);
                this.tableModel(tableModelList, datableList, tableName, table, true, tableField, relationField);
            }
            this.tableModel(tableModelList, fieldList, table, table, false, tableField, relationField);
            DbTableFieldModel dbTable = this.dbTable(linkId, table, fieldList, false, fullName);
            dbTableList.add(dbTable);
            serviceUtil.createTable(dbTableList);
            this.fieldsTableName(jsonArray, tableModelList);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("表新增错误:{}", e.getMessage());
            throw new WorkFlowException(MsgCode.FM013.get(e.getMessage()), e);
        }
        return tableModelList;
    }

    /**
     * 表名
     *
     * @param tableName
     * @param isUpperCase
     * @param isLowerCase
     * @return
     */
    private String tableName(String tableName, boolean isUpperCase, boolean isLowerCase) {
        String resultName = isUpperCase ? tableName.toUpperCase() : isLowerCase ? tableName.toLowerCase() : tableName;
        return resultName;
    }

    /**
     * 获取表单字段
     *
     * @param fieLdsModel
     * @param tableList
     */
    private void fieldList(FieLdsModel fieLdsModel, String table, List<DbFieldModel> tableList) {
        String vmodel = fieLdsModel.getVModel();
        String lable = fieLdsModel.getConfig().getLabel();
        String yunzhupaaskey = fieLdsModel.getConfig().getYunzhupaasKey();
        fieLdsModel.getConfig().setTableName(table);
        if (StringUtil.isNotEmpty(vmodel)) {
            DbFieldModel fieldForm = new DbFieldModel();
            fieldForm.setNullSign(DbFieldConst.NULL);
            fieldForm.setDataType(DtViewConst.VARCHAR);
            fieldForm.setLength("255");
            fieldForm.setIsPrimaryKey(false);
            if (StringUtil.isNotEmpty(fieLdsModel.getVModel())) {
                if (YunzhupaasKeyConsts.getTextField().contains(yunzhupaaskey)) {
                    fieldForm.setDataType(DtViewConst.TEXT);
                }
                List<String> date = new ArrayList() {
                    {
                        add(YunzhupaasKeyConsts.MODIFYTIME);
                        add(YunzhupaasKeyConsts.CREATETIME);
                        add(YunzhupaasKeyConsts.DATE);
                    }
                };
                if (date.contains(yunzhupaaskey)) {
                    fieldForm.setDataType(DtViewConst.DATE_TIME);
                }
                if (YunzhupaasKeyConsts.NUM_INPUT.equals(yunzhupaaskey)
                        || YunzhupaasKeyConsts.CALCULATE.equals(yunzhupaaskey)
                        || YunzhupaasKeyConsts.SLIDER.equals(yunzhupaaskey)) {
                    fieldForm.setDataType(DtViewConst.DECIMAL);
                    String precision = "15";
                    if (fieLdsModel.getPrecision() != null) {
                        precision = String.valueOf(fieLdsModel.getPrecision());
                    }
                    fieldForm.setLength("38," + precision);
                    // mysql 最大长度65，Oracle和postgresql最大长度38，精度0-最大长度内取值，当前系统默认给15最大
                }

                if (YunzhupaasKeyConsts.RATE.equals(yunzhupaaskey)) {
                    fieldForm.setDataType(DtViewConst.DECIMAL);
                    fieldForm.setLength("38,1");
                }

                if (YunzhupaasKeyConsts.LOCATION.equals(yunzhupaaskey)) {
                    fieldForm.setLength("500");
                }
                fieldForm.setField(vmodel);
                fieldForm.setComment(lable);
                tableList.add(fieldForm);
            }
        }
    }

    /**
     * 创建主外键字段
     *
     * @param tableList
     * @param isforeign
     */
    private void dbTableField(List<DbFieldModel> tableList, boolean isforeign, int primaryKey,
            boolean isPostgreOrKingbase, String tableField, String relationField) {
        // 是否自增 true自增
        boolean autoPrimaryKey = primaryKey == 2;
        String dataType = autoPrimaryKey ? isPostgreOrKingbase ? DtViewConst.INT : DtViewConst.BIGINT
                : DtViewConst.VARCHAR;
        DbFieldModel tableKey = new DbFieldModel();
        tableKey.setNullSign(DbFieldConst.NOT_NULL);
        tableKey.setDataType(dataType);
        tableKey.setLength(TableFeildsEnum.FID.getLength());
        tableKey.setIsPrimaryKey(true);
        tableKey.setField(relationField);
        tableKey.setIsAutoIncrement(autoPrimaryKey);
        tableKey.setComment(TableFeildsEnum.FID.getComment());
        tableList.add(tableKey);
        if (isforeign) {
            DbFieldModel tableForeignKey = new DbFieldModel();
            tableForeignKey.setNullSign(DbFieldConst.NULL);
            tableForeignKey.setDataType(dataType);
            tableForeignKey.setLength(TableFeildsEnum.FOREIGN.getLength());
            tableForeignKey.setIsPrimaryKey(false);
            tableForeignKey.setField(tableField);
            tableForeignKey.setComment(TableFeildsEnum.FOREIGN.getComment());
            tableList.add(tableForeignKey);
        }
    }

    /**
     * 组装字段list
     *
     * @param tableModelList
     * @param dbtable
     * @param table
     * @param mastTable
     * @param isforeign
     */
    private void tableModel(List<TableModel> tableModelList, List<DbFieldModel> dbtable, String table, String mastTable,
            boolean isforeign, String tableField, String relationField) {
        TableModel tableModel = new TableModel();
        tableModel.setRelationField(isforeign ? relationField : "");
        tableModel.setRelationTable(isforeign ? mastTable : "");
        tableModel.setTable(table);
        tableModel.setComment(isforeign ? "子表" : "主表");
        tableModel.setTableField(isforeign ? tableField : "");
        tableModel.setTypeId(isforeign ? "0" : "1");
        List<DbFieldVO> voList = dbtable.stream().map(DbFieldVO::new).collect(Collectors.toList());
        tableModel.setFields(JsonUtil.getJsonToList(voList, TableFields.class));
        tableModelList.add(tableModel);
    }

    /**
     * 组装创表字段
     *
     * @param linkId
     * @param tableName
     * @param tableFieldList
     * @param isforeign
     * @return
     */
    private DbTableFieldModel dbTable(String linkId, String tableName, List<DbFieldModel> tableFieldList,
            boolean isforeign, String fullName) {
        DbTableFieldModel dbTable = new DbTableFieldModel();
        dbTable.setDbLinkId(linkId);
        dbTable.setTable(tableName);
        dbTable.setDbFieldModelList(tableFieldList);
        String s = isforeign ? "子表" : "主表";
        if (fullName.contains("&")) {// 自动生成表备注的时候带&符号创建不成功问题
            fullName = fullName.replace("&", " ");
        }
        dbTable.setComment(String.format("%s-%s", fullName, s));
        return dbTable;
    }
}
