package net.tccn.base;

import dev.zhub.mk.qtask.QTask;
import lombok.Getter;
import net.tccn.base.dbq.jdbc.api.DbAccount;
import net.tccn.base.dbq.jdbc.api.DbKit;
import net.tccn.base.dbq.table.Field;
import net.tccn.dict.Dict;
import net.tccn.meta.*;
import net.tccn.plat.MPlat;
import net.tccn.qtask.TaskKit;
import net.tccn.user.MUser;
import org.redkale.annotation.Resource;
import org.redkale.convert.json.JsonConvert;
import org.redkale.service.AbstractService;
import org.redkale.source.DataJdbcSource;
import org.redkale.source.DataSource;
import org.redkale.util.AnyValue;
import org.redkale.util.Comment;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiFunction;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static java.util.Arrays.asList;

/**
 * Created by liangxianyou at 2019/1/7 13:31.
 */
public class MetaKit extends AbstractService {
    //基础数据缓存
    @Getter
    private static List<MTable> mTables;
    @Getter
    private static List<MLink> metaLinks;
    @Getter
    private static List<MService> metaServices;
    @Getter
    private static List<DbAccount> dbPlats;
    @Getter
    private static List<MPlat> mPlats;
    @Getter
    private static List<MUser> users;
    @Getter
    private static List<QTask> qTasks;
    @Getter
    private static List<Dict> dicts;

    protected static String dcate = "db";
    protected static String dataPath;
    private static final JsonConvert convert = JsonConvert.root();

    @Resource(name = "meta")
    protected DataSource metaSource;

    public <T> void reloadxAsync(Class<T> clazz) {
        CompletableFuture.runAsync(() -> {
            if (clazz == QTask.class) {
                qTasks = metaSource.queryList(QTask.class);
                TaskKit.init(qTasks);
            } else if (clazz == MPlat.class) mPlats = metaSource.queryList(MPlat.class);
            else if (clazz == DbAccount.class) dbPlats = metaSource.queryList(DbAccount.class);
            else if (clazz == MTable.class) mTables = metaSource.queryList(MTable.class);
            else if (clazz == MService.class) metaServices = metaSource.queryList(MService.class);
            else if (clazz == MLink.class) metaLinks = metaSource.queryList(MLink.class);
            else if (clazz == Dict.class) dicts = metaSource.queryList(Dict.class);
            /*if (clazz == MUser.class) {
                users = metaSource.queryList(MUser.class);
            }*/
        });
    }

    @Override
    public void init(AnyValue config) {
        reloadxAsync(QTask.class);
        reloadxAsync(MPlat.class);
        reloadxAsync(DbAccount.class);
        reloadxAsync(MService.class);
        reloadxAsync(MTable.class);
        reloadxAsync(MLink.class);
        // reloadxAsync(Dict.class);


        /*metaTables.forEach(x -> {
            // 写入到  MTable
            MTable mTable = new MTable();
            mTable.setTableid(Integer.parseInt(x.getKey()));
            mTable.setCatalog(x.getCatalog());
            mTable.setDbid(x.getDbid());
            mTable.setAlias(x.getAlias());
            mTable.setTablename(x.getName());
            mTable.setPlatid(x.getPlatid());
            mTable.setComment(x.getComment());
            mTable.setItems(x.getItems());

            metaSource.insertAsync(mTable);
        });*/
        /*metaServices.forEach(x -> {
            // 写入到  MService
            MService service = new MService();
            service.setServid(Integer.parseInt(x.getKey()));
            service.setName(x.getName());
            service.setTablealias(x.getTable());
            service.setShows(x.getShows());
            service.setExports(x.getExports());
            service.setEdits(x.getEdits());
            service.setDetails(x.getDetails());
            service.setFilters(x.getFilters());
            service.setComment(x.getComment());
            //service.setDels(x.getDels());
            service.setPlatid(x.getPlatid());

            metaSource.insert(service);
        });*/
        /*metaLinks.forEach(x -> {
            MxLink link = new MxLink();
            link.setLinkid(Integer.parseInt(x.getKey()));
            link.setTables(x.getTables());
            link.setLinks(x.getLink());
            metaSource.insert(link);
        });*/
    }

    // -----------------------------------
    public static void init() {
        // reload(MetaTable.class);
        // reload(MLink.class);
        // reload(MetaService.class);
        // reload(DbAccount.class);
        // reload(MetaPlat.class);
        // reload(MetaUser.class);
        // reload(DbTask.class);
        // reload(Dict.class);

        /*
        同步 本地文件配置数据到 数据库
        List<List<? extends Doc>> list = asList(metaTables, metaLinks, metaServices, dbPlats, sysPlats, users, taskEntities, dicts);
        for (List<? extends Doc> docs : list) {
            for (Doc doc : docs) {
                doc.save();
            }
        }*/

    }

    /*public static <T extends Doc> void reload(Class<T> clazz) {
        reload(clazz, null);
    }

    public static <T extends Doc> void reload(T t) {
        reload(t.getClass(), t.getKey());
    }*/

    /*public static void main(String[] args) throws IOException {
        Type type = new TypeToken<List<DbAccount>>() {
        }.getType();
        dbPlats = FileKit.readAs(new File("D:\\Java\\meta-kit\\conf\\data\\DbAccount.json"), type);
        //convert.convertFrom(type,"[{\"catalogs\":[\"test\"],\"cate\":\"mysql\",\"id\":\"db_plat/67275393\",\"key\":\"67275393\",\"name\":\"ylz测试\",\"url\":\"jdbc:mysql://119.3.106.117:3306\",\"user\":\"root\"},{\"catalogs\":[\"v09x_platf_core\"],\"cate\":\"mysql\",\"id\":\"db_plat/67275392\",\"key\":\"67275392\",\"name\":\"platf_qc\",\"url\":\"jdbc:mysql://121.196.17.55:6063\",\"user\":\"root\"},{\"catalogs\":[\"official_core\",\"official_ipci\",\"v09x_platf_core\",\"platf_quest\",\"platf_pay\",\"platf_mall\",\"platf_oth\",\"platf_im\",\"z_core\"],\"cate\":\"mysql\",\"id\":\"db_plat/67275391\",\"key\":\"67275391\",\"name\":\"platf_pro\",\"url\":\"jdbc:mysql://122.112.180.156:6033\",\"user\":\"guest\"},{\"catalogs\":[\"db_diamond\"],\"id\":\"db_plat/53533152\",\"key\":\"53533152\",\"name\":\"钻石项目\",\"url\":\"jdbc:mysql://192.168.201.51:3306/db_diamond?characterEncoding=utf-8&autoReconnect=true&serverTimezone=Asia/Shanghai&useSSL=false\",\"user\":\"root\"},{\"catalogs\":[\"db_diamond\"],\"id\":\"db_plat/53532996\",\"key\":\"53532996\",\"name\":\"钻石项目\",\"url\":\"jdbc:mysql://192.168.201.51:3306/db_diamond?characterEncoding=utf-8&autoReconnect=true&serverTimezone=Asia/Shanghai&useSSL=false\",\"user\":\"root\"},{\"catalogs\":[\"platf_im\",\"v09x_platf_core\",\"platf_oss\",\"platf_quest\",\"platf_oth\",\"sport_oss\",\"zhub\",\"cpg_core\",\"z_core\",\"z_config\",\"z_im\",\"z_mall\",\"z_quest\",\"z_oss\",\"z_oth\",\"cmt_oss\",\"cmt_depot_core\",\"cmt_core\",\"sport_core\"],\"cate\":\"mysql\",\"id\":\"db_plat/52481174\",\"key\":\"52481174\",\"name\":\"platf_dev\",\"url\":\"jdbc:mysql://47.111.150.118:6063\",\"user\":\"root\"},{\"catalogs\":[],\"cate\":\"mysql\",\"id\":\"db_plat/4375768\",\"key\":\"4375768\",\"name\":\"mysql数据库\",\"url\":\"jdbc:mysql://192.168.50.124:3306/mytest?characterEncoding=utf-8&autoReconnect=true&useSSL=false&connectTimeout=3000\",\"user\":\"root\"},{\"catalogs\":[],\"cate\":\"mysql\",\"id\":\"db_plat/4267761\",\"key\":\"4267761\",\"name\":\"测试\",\"remark\":\"sadfdsaf\",\"url\":\"123&connectTimeout=5000\",\"user\":\"root\"},{\"catalogs\":[\"db_art\",\"db_jsons_bbs\",\"db_mater\",\"db_redbbs\",\"jfly\",\"redbbs_dev\",\"meta_kit_test\"],\"cate\":\"mysql\",\"id\":\"db_plat/3321254\",\"key\":\"3321254\",\"name\":\"测试-DB【可用】\",\"url\":\"jdbc:mysql://120.24.230.60:3306/redbbs?characterEncoding=utf-8&autoReconnect=true&useSSL=false&connectTimeout=3000\",\"user\":\"guest\"},{\"catalogs\":[\"blockchain\",\"gxbii_dev\",\"gxbii_all\",\"gxbii_cmd\",\"fzexp\",\"db_fz\",\"a_test\",\"meta_xx\",\"ipsm_v4\"],\"cate\":\"mysql\",\"id\":\"db_plat/3305916\",\"key\":\"3305916\",\"name\":\"测试库-11测试库【可用】\",\"remark\":\"描述\",\"url\":\"jdbc:mysql://192.168.202.11:3306/gxbii_dev?characterEncoding=utf-8&autoReconnect=true&connectTimeout=3000\",\"user\":\"root\"},{\"catalogs\":[\"ipsm_v4\"],\"cate\":\"mysql\",\"id\":\"db_plat/32822760\",\"key\":\"32822760\",\"name\":\"ceshi1111\",\"url\":\"jdbc:mysql://192.168.202.11:3306/ipsm_v4?characterEncoding=utf-8&autoReconnect=true\",\"user\":\"root\"},{\"catalogs\":[\"zbd_v1\"],\"cate\":\"mysql\",\"id\":\"db_plat/27166384\",\"key\":\"27166384\",\"name\":\"测试1\",\"url\":\"jdbc:mysql://192.168.50.124:3306/mytest?characterEncoding=utf-8&autoReconnect=true&useSSL=false&connectTimeout=3000\",\"user\":\"root\"},{\"catalogs\":[],\"cate\":\"mysql\",\"id\":\"db_plat/25668979\",\"key\":\"25668979\",\"name\":\"测试Mysql数据库\",\"url\":\"jdbc:mysql://558cfc37a10ef.sh.cdb.myqcloud.com:3817/demo?autoReconnect=true\",\"user\":\"cdb_outerroot\"},{\"catalogs\":[],\"cate\":\"localApi\",\"id\":\"db_plat/23090860\",\"key\":\"23090860\",\"name\":\"平台本地API\"},{\"catalogs\":[],\"cate\":\"http\",\"id\":\"db_plat/21561306\",\"key\":\"21561306\",\"name\":\"http地址调用\",\"url\":\"http://127.0.0.1/plat/db_list\"},{\"catalogs\":[\"tc\",\"tc_bbs\",\"redbbs\",\"redoss\",\"material\",\"keeper_dev\",\"art123\",\"keeper\",\"db_party\"],\"cate\":\"mysql\",\"id\":\"db_plat/21558770\",\"key\":\"21558770\",\"name\":\"TX-cloud\",\"url\":\"jdbc:mysql://558cfc37a10ef.sh.cdb.myqcloud.com:3817/demo?autoReconnect=true\",\"user\":\"cdb_outerroot\"},{\"catalogs\":[\"feature_test\",\"intelligence\",\"ma\",\"mysql\",\"ma1\",\"ma2\",\"maintenance\",\"zhaobiao\",\"zhaobiao2\"],\"cate\":\"mysql\",\"id\":\"db_plat/21449811\",\"key\":\"21449811\",\"name\":\"物联网-jj【可用】\",\"url\":\"jdbc:mysql://192.168.50.21:3306/wlw?characterEncoding=utf-8&autoReconnect=true&serverTimezone=Asia/Shanghai\",\"user\":\"root\"},{\"catalogs\":[],\"id\":\"db_plat/20982257\",\"key\":\"20982257\",\"name\":\"数据平台abc\",\"remark\":\"sadfdsaf\",\"url\":\"123&connectTimeout=5000\",\"user\":\"root\"}]");
        System.out.println(dbPlats.size());
    }*/

    /*public static <T extends Doc> void reload(Class<T> clazz, String key) {
        try {
            File file = new File(String.format("%s%s.json", dataPath, clazz.getSimpleName()));
            if ("file".equals(dcate)) {
                *//*if (MetaTable.class == clazz) {
                    Type type = new TypeToken<List<MetaTable>>() {
                    }.getType();
                    metaTables = FileKit.readAs(file, type);
                } else*//*
     *//*if (MLink.class == clazz) {
                    Type type = new TypeToken<List<MLink>>() {
                    }.getType();
                    metaLinks = FileKit.readAs(file, type);
                }*//* *//*else if (MetaService.class == clazz) {
                    Type type = new TypeToken<List<MetaService>>() {
                    }.getType();
                    metaServices = FileKit.readAs(file, type);
                }*//* *//*else if (DbAccount.class == clazz) {
                    Type type = new TypeToken<List<DbAccount>>() {
                    }.getType();
                    dbPlats = FileKit.readAs(file, type);
                }*//* *//*else if (MetaDb.class == clazz) {
                    Type type = new TypeToken<List<DbAccount>>() {
                    }.getType();
                    dbPlats = FileKit.readAs(file, type);;
                }*//* *//*else if (MetaPlat.class == clazz) {
                    Type type = new TypeToken<List<MetaPlat>>() {
                    }.getType();
                    mPlats = FileKit.readAs(file, type);;
                } *//* *//*else if (MetaUser.class == clazz) {
                    Type type = new TypeToken<List<MetaUser>>() {
                    }.getType();
                    users = FileKit.readAs(file, type);;
                }*//* *//*else if (DbTask.class == clazz) {
                    Type type = new TypeToken<List<DbTask>>() {
                    }.getType();
                    taskEntities = FileKit.readAs(file, type);;
                } *//* *//*else if (Dict.class == clazz) {
                    Type type = new TypeToken<List<Dict>>() {
                    }.getType();
                    dicts = FileKit.readAs(file, type);
                }*//*
            } else {
                *//*if (MetaTable.class == clazz) {
                    metaTables = MetaTable.dao.find();
                }
                else*//*
                //if (MLink.class == clazz) metaLinks = MLink.dao.find();
                //else if (MetaService.class == clazz) metaServices = MetaService.dao.find();
                //else if (DbAccount.class == clazz) dbPlats = DbAccount.dao.find();
                //else if (MetaDb.class == clazz) dbPlats = DbAccount.dao.find();
                //else if (MetaPlat.class == clazz) mPlats = MetaPlat.dao.find();
                //else if (MetaUser.class == clazz) users = MetaUser.dao.find();
                *//*else if (DbTask.class == clazz) {
                    // taskEntities = DbTask.dao.find();
                    // TaskKit.init();
                }*//*
                //else
                *//*if (Dict.class == clazz) {
                    dicts = Dict.dao.find();
                }*//*
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }*/

    /*public static void cacheSave() {
        //cacheSave(MetaTable.class);
        //cacheSave(MLink.class);
        //cacheSave(MService.class);
        //cacheSave(DbAccount.class);
        //cacheSave(MetaPlat.class);
        //cacheSave(MetaUser.class);
        //cacheSave(DbTask.class);
        //cacheSave(Dict.class);
    }*/

    /*private static void cacheSave(Class clazz) {
        List list = null;
        *//*if (MetaTable.class == clazz) list = metaTables;
        else*//*
        if (MLink.class == clazz) list = metaLinks;
        else if (MService.class == clazz) list = metaServices;
            //else if (DbAccount.class == clazz) list = dbPlats;
            //else if (MetaPlat.class == clazz) list = mPlats;
            //else if (MetaUser.class == clazz) list = users;
            // else if (DbTask.class == clazz) list = taskEntities;
        else if (Dict.class == clazz) list = dicts;

        if (list == null || list.size() == 0) return;

        File file = new File(String.format("%s%s.json", dataPath, list.get(0).getClass().getSimpleName()));
        file.getParentFile().mkdirs();
        FileKit.strToFile(MetaKit.convert.convertTo(list), file);
    }*/

    /**
     * 得到业务主表
     *
     * @param serviceName
     * @param token
     * @return
     */
    public static MTable getMainTable(String serviceName, String token) {
        MService metaService = MetaKit.getMetaService(serviceName, token);
        return MetaKit.getMetaTableByAlias(metaService.getTablealias());
    }

    /**
     * 通过平台token 得到平台字典数据
     *
     * @param plattoken
     */
    public static Map<String, List<Dict>> getDictData(String plattoken) {
        /*Integer platId = MetaKit.getPlatId(plattoken);
        Map<String, List<Dict>> dicts = MetaKit.dicts.stream().filter(x -> x.getPlatid() == (int) platId).collect(Collectors.groupingBy(Dict::getType));
        return dicts;*/
        return new HashMap<>();
    }

    // -----------------------------------
    public void cleanData() {

    }

    /**
     * 通过 别名 查询 MetaTable
     *
     * @param alias
     * @return
     */
    public static MTable getMetaTableByAlias(String alias) {
        Optional<MTable> table = mTables.stream().filter(x -> x.getAlias().equals(alias)).findAny();
        return table.orElse(null);
    }

    public static MTable getMetaTable(String name, String token) {
        Optional<MTable> any = getMTables().stream().filter(x -> {
            return x.getTablename().equals(name) && x.getPlatid().equals(getPlatId(token));
        }).findAny();

        return any.get();
    }

    public static MService getMetaService(String name, String token) {
        Optional<MService> service = metaServices.stream()
                .filter(x -> x.getName().equals(name) && x.getPlatid().equals(getPlatId(token)))
                .findAny();
        return service.orElse(null);
    }

    //字段特征排序
    public static BiFunction<MTable, String[], MTable> sortItem = (t, arr) -> {
        List<Field> items = t.getItems();

        //x 是跨越值
        a:
        for (int i = 0, x = 0; i < arr.length; i++) {
            int inx = i - x;

            if (!items.get(inx).equals(arr[i])) {
                Field tmp = items.get(inx);
                for (int j = inx + 1; j < items.size(); j++) {
                    if (items.get(j).equals(arr[i])) {
                        items.set(inx, items.get(j));
                        items.set(j, tmp);
                        continue a;
                    }
                }

                //运行到这里，说明在  list 中找不到排序标识对应的数据， 让排序角标差值+1
                x++;
            }
        }
        t.setItems(items);
        return t;
    };

    public static Map cfg(String name, String token) {
        MService metaService = getMetaService(name, token);
        Kv<String, MTable> metaTables = getMTables(metaService, false);

        List<Map<String, String>> shows = metaService.getShows();
        List<FromItem> edits = metaService.getEdits();
        List<Map<String, String>> details = metaService.getDetails();
        List<Filter> filters = metaService.getFilters();
        String comment = metaService.getComment();

        //List<Field> items = new ArrayList<>();
        /*Kv<String, Kv<String, Kv>> _items2 = Kv.of();
        metaTables.forEach((k, v) -> {
            Kv<String, Kv> _items = Kv.of();
            v.getItems().forEach(x -> {
                Kv kv = Kv.of();
                kv.set("col", x.getName());
                kv.set("label", x.getLabel());
                kv.set("InExt", x.getInExt());
                kv.set("inType", x.getInType());
                kv.set("expr", x.showField());
                _items.set(x.getName(), kv);
            });

            _items2.set(k, _items);
        });*/

        //shows
        /*List _shows = new ArrayList();
        shows.forEach(x -> {
            MetaTable metaTable = metaTables.get(x.split("[.]")[0]); // 表别名
            metaTable.getItems().stream()
                    .filter(y -> x.split("[.]")[1].equals(y.getName()))
                    .findFirst().ifPresent(y -> _shows.add(Kv.of("col", x).set("order", true)));
        });*/
        /*List<Kv> _shows = shows.stream().map(x -> {
            Kv kv = Kv.of();
            kv.putAll(x);

            if ("FUNC".equalsIgnoreCase(x.get("inType")) || "QTASK".equalsIgnoreCase(x.get("inType")) || "DICT".equalsIgnoreCase(x.get("inType"))) {
                kv.set("fmt", x.get("inType") + "|" + x.get("inExt"));
            } else if ("HIDDEN".equalsIgnoreCase(x.get("inType"))) {
                kv.set("fmt", "HIDDEN");
            } else {
                kv.set("fmt", "");
            }
            kv.remove("inType");
            kv.remove("inExt");
            return kv;
        }).collect(Collectors.toList());*/


        //filters
        /*List<Map> _filters = new ArrayList<>();
        filters.forEach(x -> {
            String col = String.valueOf(x.getName());
            MetaTable metaTable = metaTables.get(col.split("[.]")[0]); // 表别名

            Kv filter = Kv.of();
            metaTable.getItems().stream()
                    .filter(y -> col.split("[.]")[1].equals(y.getName()))
                    .findFirst()
                    .ifPresent(y -> {
                        filter.set("name", x.getName());
                        filter.set("label", x.getLabel() != null ? x.getLabel() : y.getLabel());
                        List<Kv> types = new ArrayList<>();
                        List<String> list = (List) x.getFilterType();
                        list.forEach(t -> {
                            FilterType type = FilterType.getFilterType(t);
                            if (type != null) {
                                types.add(Kv.of("name", t).set("remark", type.getRemark()));
                            }
                        });

                        filter.set("filterType", types);
                        if (!types.isEmpty()) {//设置默认查询项
                            filter.set("type", types.get(0).get("name"));
                        }
                        filter.set("checked", x.isChecked());
                    });
            _filters.add(filter);
        });*/

        //edits
        //List _edits = new ArrayList();//edits;
        /*edits.forEach(x -> {
            Kv kv = Kv.of();
            kv.set("col", x);

            String col = x.get("col") + "";
            //readonly,hidden
            if ("id".equalsIgnoreCase(col)) {
                kv.set("upAttr", "hidden");
                kv.set("addAttr", "none");
            }
            if ("reportWay".equalsIgnoreCase(col)) {
                kv.set("upAttr", "readonly");
                kv.set("addAttr", "none");
            }
            if ("insertTime".equalsIgnoreCase(col)) {
                kv.set("upAttr", "readonly");
                kv.set("addAttr", "none");
            }

            if ("ip".equalsIgnoreCase(col)) {
                kv.set("ck", "ip");
            }

            _edits.add(kv);
        });*/

        //details
        /*List _details = new ArrayList();//details;
        details.forEach(x -> {
            Kv kv = Kv.of();
            kv.set("col", x);

            _details.add(kv);
        });*/

        //pk：业务主表的主键
        StringBuffer _pks = new StringBuffer();
        MTable mainTable = metaTables.get(metaService.getTablealias());
        mainTable.getItems().stream().filter(x -> x.getPk() != null && x.getPk()).forEach(x -> {
            _pks.append(String.format("%s.%s,", metaService.getTablealias(), x.getName()));
        });
        if (_pks.length() > 0) {
            _pks.deleteCharAt(_pks.length() - 1);
        }
        if (_pks.length() == 0) { // 默认主键
            List<Field> items = metaTables.get(metaService.getTablealias()).getItems();
            //存在id字段，取id
            items.stream().filter(x -> x.getName().equalsIgnoreCase("id")).findAny().ifPresent(x -> {
                _pks.append(String.format("%s.%s", metaService.getTablealias(), x.getName()));
            });
        }

        return Kv.of()
                .set("pk", _pks.toString())
                .set("title", comment)
                //.set("items", _items2)
                .set("shows", shows)
                .set("filters", filters)
                .set("edits", edits)
                .set("details", details);
    }

    @Comment("获取导出excel表头配置k-v")
    public static Kv cfgExport(String name, String token) {
        MService metaService = getMetaService(name, token);
        List<Map<String, String>> exports = metaService.getExports();

        Kv kv = Kv.of(); // {col:label}
        exports.forEach(x -> {
            kv.put(x.get("col"), x.get("label"));
        });
        return kv;
    }

    //itemUpdate
    public static BiFunction<MTable, List<Field>, MTable> itemUpdate = (t, fields) -> {
        List<Field> items = t.getItems();
        for (int i = 0; i < fields.size(); i++) {
            for (int j = 0; j < items.size(); j++) {
                if (items.get(j).equals(fields.get(i).getName())) {
                    items.set(j, fields.get(i));
                }
            }
        }
        return t;
    };

    //showUpdate
    /*public static BiFunction<String, List<String>, MetaService> showUpdate = (name, shows) -> {

        MetaService metaService = getMetaService(name, "");

        MetaService _metaService = MetaService.dao.findByKey(metaService.getKey());
        _metaService.setShows(shows);
        _metaService.update();

        metaService.setShows(shows);//更新缓存
        return metaService;
    };*/


    public static MTable getMetaTableByKey(int key) {
        return mTables.stream().filter(x -> x.getTableid() == key).findAny().orElse(null);
    }

    public static List<MLink> getMetaLinks(String t, List<String> shows, List<String> filters) {


        Predicate<String> contain = s -> {
            for (String item : shows) {
                if (s.equals(item.split("[.]")[0])) {
                    return true;
                }
            }
            for (String item : filters) {
                if (s.equals(item.split("[.]")[0])) {
                    return true;
                }
            }
            return false;
        };

        //得到直接关联
        //1、直接关联 表： t.equals(x.getTables()[0]) || t.equals(x.getTables()[1]
        //2、关联且有过滤：
        //3、关联有展示：
        List<MLink> links = metaLinks.stream()
                .filter(x -> {
                    return (t.equals(x.getTables()[0]) || t.equals(x.getTables()[1]))
                            && (contain.test(x.getTables()[0]) || contain.test(x.getTables()[1]));
                })
                .collect(Collectors.toList());
        return links;
    }

    public static Kv buildeDetail(MService metaService) {
        //tables
        Kv<String, MTable> tables = getMTables(metaService, true);
        return Kv.of("tables", tables)
                .set("links", Kv.of());
    }

    public static Kv<String, MTable> getMTables(MService metaService, Boolean all) {
        Kv<String, MTable> tables = Kv.of();

        String table = metaService.getTablealias();//
        tables.set(table, getMetaTableByAlias(table));

        //收集所有的col
        Set<String> allAlias;

        if (!all) {
            allAlias = Utils.concat(
                    metaService.getFilters().stream().map(f -> {
                        String col = (String) f.getName();
                        String alias = col.split("[.]")[0];
                        return alias;
                    }),
                    metaService.getExports().stream().map(x -> x.get("col").split("[.]")[0]),
                    metaService.getShows().stream().map(x -> x.get("col").split("[.]")[0])/*,  todo: xxx
                    metaService.getEdits().stream().map(x -> x.split("[.]")[0])*/
            ).collect(Collectors.toSet());

        } else {
            allAlias = new HashSet<>();
            metaLinks.stream().forEach(x -> {
                if (table.equals(x.getTables()[0])) {
                    allAlias.add(x.getTables()[1]);
                } else if (table.equals(x.getTables()[1])) {
                    allAlias.add(x.getTables()[0]);
                }
            });
        }

        allAlias.forEach(x -> tables.set(x, getMetaTableByAlias(x)));
        return tables;
    }

    /*public static DbKit getDbKit(int dbid) {
        Optional<DbAccount> dbAccount = dbPlats.stream().filter(x -> x.getKey().equals(dbid)).findAny();

        return new DbKit(dbAccount.get());
    }*/
    public static DbKit getDbKit(int dbid, String catalog) {
        Optional<DbAccount> dbAccount = dbPlats.stream().filter(x -> x.getDbid() == dbid).findAny();
        return new DbKit(dbAccount.get(), catalog);
    }

    public static DbAccount getDbPlat(int dbid) {
        Optional<DbAccount> db = dbPlats.stream().filter(x -> x.getDbid() == dbid).findFirst();

        return db.get();
    }

    @Comment("通过平台token  得到平台id")
    public static Integer getPlatId(String plattoken) { //
        Optional<MPlat> plat = mPlats.stream().filter(x -> x.getPlattoken().equals(plattoken)).findAny();
        return plat.get().getPlatid();
    }

    public static String lastAlias;

    public String nextAlias() {
        if (lastAlias == null) {
            //String aql = TplKit.use(true).getTpl("metaTable.lastAlias");
            lastAlias = findColumn("mable.lastAlias", Kv.of(), String.class);
            // lastAlias = MetaTable.dao.findFirst(aql, String.class); // TODO....
        }
        return lastAlias = next(lastAlias, "");
    }

    //使用['a',...,'z'] 创建Table 别名
    private static String next(String x, String end) {
        if (x == null || "".equals(x)) {
            return "a" + end;
        }
        char c = x.charAt(x.length() - 1);
        String sub = x.substring(0, x.length() - 1);
        if (c < 'z') {
            return sub + (++c) + end;
        } else if (c == 'z') {
            return next(sub, "a" + end);
        }
        return null;
    }

    public static List<String> tableExist(String[] tableArr, String token) {
        List<String> _tableArr = asList(tableArr);
        List<String> hv = mTables.stream()
                .filter(x -> _tableArr.contains(x.getTablename()) && x.getPlatid().equals(getPlatId(token)))
                .map(MTable::getTablename)
                .collect(Collectors.toList());
        return hv;
    }

    // ---------------------- repository -------------------
    public void save(MTable table) {
        if (table.getTableid() == null || table.getTableid() == 0) {
            metaSource.insert(table);
            mTables.add(table);
        } else {
            metaSource.update(table);

            // 更新缓存
            mTables.stream().filter(x -> x.getTableid().equals(table.getTableid())).forEach(x -> {
                x.setCatalog(table.getCatalog());
                x.setComment(table.getComment());
                x.setDbid(table.getDbid());
                x.setItems(table.getItems());
                x.setPlatid(table.getPlatid());
                x.setStatus(table.getStatus());
                x.setTablename(table.getTablename());
                x.setAlias(table.getAlias());
            });
        }

    }

    public void save(MService mservice) {
        if (mservice.getServid() == 0) {
            metaSource.insert(mservice);
            metaServices.add(mservice);
        } else {
            metaSource.update(mservice);

            metaServices.stream().filter(x -> x.getServid() == mservice.getServid()).forEach(x -> {
                x.setComment(mservice.getComment());
                x.setEdits(mservice.getEdits());
                x.setDetails(mservice.getDetails());
                x.setExports(mservice.getExports());
                x.setFilters(mservice.getFilters());
                x.setName(mservice.getName());
                x.setPlatid(mservice.getPlatid());
                x.setShows(mservice.getShows());
                x.setTablealias(mservice.getTablealias());
            });
        }
    }

    public void save(MLink link) {
        if (link.getLinkid() == 0) {
            metaSource.insert(link);
            metaLinks.add(link);
        } else {
            metaSource.update(link);

            metaLinks.stream().filter(x -> x.getLinkid() == link.getLinkid()).forEach(x -> {
                x.setLinks(link.getLinks());
                x.setTables(link.getTables());
            });
        }
    }

    /*public static <T extends Doc> void save(T... ts) {
        if (ts == null || ts.length == 0) return;

        for (T t : ts) {
            if ("file".equals(dcate)) {
                if (t.getKey() == null) { //数据新增异常提示
                    throw new UnsupportedOperationException("数据文件形式启动服务，不支持配置新增！");
                }

                cacheSave(t.getClass());
                return;
            }

            if (t.getKey() == null) {
                t.save();
            } else {

                *//*if (t instanceof MLink) {
                    //避免删除属性无效
                    if (((MLink) t).getLink() != null && ((MLink) t).getLink().size() > 0) {
                        t.find(String.format("UPDATE '%s' WITH { link:null  } IN MetaLink", t.getKey()), Map.class);
                    }
                }*//*

                t.update();
            }
        }

        reload(ts[0].getClass());
    }*/

    /*public static <T extends Doc> T findFirst(T t) {
        Objects.nonNull(t);

        List<T> list = asList();
        Map doc = t.toDoc();
        if (t instanceof MetaUser) {
            list = (List<T>) users;
        }

        Optional any = list.stream().filter(x -> {
            Map map = x.toDoc();
            Set<String> keySet = doc.keySet();
            for (String k : keySet) {
                if (doc.get(k) != null && (doc.get(k) instanceof String && doc.get(k).equals(map.get(k)))) {
                    return true;
                }
            }
            return false;
        }).findAny();

        return (T) any.orElse(null);
    }*/


    protected static TplKit tplKit = TplKit.use(true);

    protected <T> T findColumn(String tpl, Map params, Class<T> type) {
        String sql = tplKit.getTpl(tpl, params);
        return ((DataJdbcSource) metaSource).nativeQueryOne(type, sql);
    }
}
