package net.tccn.plat;

import net.tccn.base.BaseService;
import net.tccn.base.JBean;
import net.tccn.base.Kv;
import net.tccn.base.MetaKit;
import net.tccn.base.dbq.jdbc.api.DbAccount;
import net.tccn.base.dbq.jdbc.api.DbKit;
import net.tccn.base.dbq.table.Column;
import net.tccn.base.dbq.table.Table;
import net.tccn.meta.MTable;
import org.redkale.net.http.RestMapping;
import org.redkale.net.http.RestService;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Stream;

@RestService(automapping = true, comment = "数据库操作类")
public class _DbService extends BaseService {

    @RestMapping(name = "catalog_list", comment = "获取数据源的database")
    public JBean catalogList(DbAccount dbAccount, int dbid) {
        JBean jBean = new JBean();
        DbKit dbKit = null;
        if (dbAccount != null) {
            dbKit = new DbKit(dbAccount, "");
        } else {
            dbKit = MetaKit.getDbKit(dbid, "");
        }

        List<Map> list = dbKit.queryList("SHOW DATABASES;", Map.class);

        Stream<String> database = list.stream().map(x -> String.valueOf(x.get("Database")));

        return jBean.setBody(database.toArray());
    }

    @RestMapping(name = "table_list", comment = "数据库表列表")
    public List<Table> tableList(int dbid, String catalog, String[] tables) {
        DbKit dbKit = MetaKit.getDbKit(dbid, "");

        String sql = tplKit.getTpl("db.table_list", Kv.of("catalog", catalog).set("tables", tables));
        return dbKit.queryList(sql, Table.class);
    }

    @RestMapping(ignore = true)
    public List<Table> tableInfoList(int dbid, String catalog, String[] tables) {
        List<Table> list = new ArrayList<>(tables.length);
        for (String table : tables) {
            list.add(tableInfo(dbid, catalog, table));
        }
        return list;
    }

    @RestMapping(name = "table_info", comment = "数据库表详情")
    public JBean MetatableInfo(int dbid, String catalog, String tableName) {
        JBean jBean = new JBean();
        try {
            Table table = tableInfo(dbid, catalog, tableName);

            jBean.setBody(MTable.toAs(table));
        } catch (Exception e) {
            jBean.set(-1, "查询表信息失败");
            new IllegalArgumentException("查询表信息失败", e);
        }
        return jBean;
    }

    @RestMapping(ignore = true, comment = "查询表信息")
    public Table tableInfo(int dbid, String catalog, String tableName) {
        DbKit dbKit = MetaKit.getDbKit(dbid, catalog);

        String sql = tplKit.getTpl("db.table_list", Kv.of("table", tableName));
        String columnSql = String.format("SHOW FULL COLUMNS FROM %s.`%s`", catalog, tableName);

        CompletableFuture<Table> tableFuture = dbKit.findAsync(sql, Table.class);
        CompletableFuture<List<Column>> columnFuture = dbKit.queryListAsync(columnSql, Column.class);

        try {
            Table table = tableFuture.get();
            table.setColumns(columnFuture.get());

            return table;
        } catch (InterruptedException | ExecutionException e) {
            new IllegalArgumentException("查询表信息失败", e);
        }
        return null;
    }

    @RestMapping(name = "table_create", comment = "新建表[mysql]")
    public JBean tableCreate(int dbid, String catalog, String sql) {
        JBean jBean = new JBean();

        DbKit dbKit = MetaKit.getDbKit(dbid, catalog);
        dbKit.createTable(sql);

        return jBean;
    }

    // 比对表结构
    /*@RestMapping(name = "table_compare", comment = "对比表结构")
    public Kv tableCompare(String dbPlatA, String dbPlatB, String catalog) {
        String sql = String.format("SELECT table_name 'tableName', column_name 'columnName', column_comment 'columnComment',column_type 'columnType',column_default 'columnDefault', is_nullable 'isNullable'" +
                " FROM INFORMATION_SCHEMA.COLUMNS" +
                " WHERE table_schema = '%s'", catalog);

        List<Column> listA = MetaKit.getDbKit(dbPlatA, catalog).queryList(sql, Column.class);
        List<Column> listB = MetaKit.getDbKit(dbPlatB, catalog).queryList(sql, Column.class);

        Map<String, List<Column>> ddlA = Utils.group(listA, Column::getTableName);
        Map<String, List<Column>> ddlB = Utils.group(listB, Column::getTableName);


        Set<String> same = new HashSet<>();  // table_name;
        List<Kv<String, Object>> differ = new ArrayList<>(); // 不相同的表，以及对应 A、B库的字段信息如：[{"tableName": "", A: [{}], B: [{}], dif: [{}] }]
        Kv<String, List<Table>> without = Kv.of(); // A,B不在对方库的表，如：{A: [{}], B: [{}]}


        ddlA.forEach((tableName, columns) -> {
            // A 有，B 无
            if (!ddlB.containsKey(tableName)) {
                List<Table> tables = without.getOrDefault("A", new ArrayList<>());
                tables.add(new Table(tableName, columns));
                without.set("A", tables);
            }

            // TODO 相同 、差异比较
            List<Column> columns2 = ddlB.get(tableName);
            if (columns2 == null) {
                return;
            }
            List<Kv<String, Object>> dif = new ArrayList<>();
            for (Column column : columns) {
                Column column2 = columns2.stream().filter(c -> c.getColumnName().equals(column.getColumnName())).findFirst().orElse(null);

                if (column2 == null) {
                    dif.add(Kv.of("column", column.getColumnName()).set("diff", "column not exist in B"));
                } else {
                    if (!column.getColumnName().equals(column2.getColumnName())) {
                        dif.add(Kv.of("column", column.getColumnName()).set( "diff", "column name not same"));
                    }
                    if (!column.getColumnComment().equals(column2.getColumnComment())) {
                        dif.add(Kv.of("column", column.getColumnName()).set( "diff", "column comment not same"));
                    }
                    if (!column.getColumnType().equals(column2.getColumnType())) {
                        dif.add(Kv.of("column", column.getColumnName()).set( "diff", "column type not same"));
                    }
                    if (!column.getColumnDefault().equals(column2.getColumnDefault())) {
                        dif.add(Kv.of("column", column.getColumnName()).set( "diff", "column default not same"));
                    }
                    if (!column.getIsNullable().equals(column2.getIsNullable())) {
                        dif.add(Kv.of("column", column.getColumnName()).set( "diff", "column nullable not same"));
                    }
                }
            }
            // columns2 中有 columns 中没有
            for (Column column2 : columns2) {
                if (!columns.stream().anyMatch(c -> c.getColumnName().equals(column2.getColumnName()))) {
                    dif.add(Kv.of("column", column2.getColumnName()).set( "diff", "column not exist in A"));
                }
            }

            if (dif.size() > 0) {
                differ.add(Kv.of("tableName", tableName).set( "A", columns).set( "B", columns2).set( "dif", dif));
            }
        });
        // B 有，A 无
        ddlB.forEach((tableName, columns) -> {
            if (ddlA.containsKey(tableName)) {
                return;
            }
            List<Table> tables = without.getOrDefault("B", new ArrayList<>());
            tables.add(new Table(tableName, columns));
            without.set("B", tables);
        });

        Kv retKv = Kv.of(); // 返回结果
        retKv.set("same", same);
        retKv.set("differ", differ);
        retKv.set("without", without);
        return retKv;
    }

    @Getter
    @Setter
    static class Table {
        String tableName;
        List<Column> columns;

        public Table(String tableName, List<Column> columns) {
            this.tableName = tableName;
            this.columns = columns;
        }
    }

    @Getter
    @Setter
    static class Column {
        @ConvertColumn(ignore = true)
        private String tableName;
        private String columnName;
        private String columnComment;
        private String columnType;
        private String columnDefault;
        private String isNullable;
    }*/

}
