package net.tccn.dbq.parser;

import net.tccn.base.Kv;
import net.tccn.base.MetaKit;
import net.tccn.dbq.fbean.*;
import net.tccn.meta.MetaLink;
import net.tccn.meta.MetaService;
import net.tccn.meta.MetaTable;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * 查询的数据是否同库，
 * 是：支持副表过滤
 * 否：只支持主表过滤
 * Created by liangxianyou at 2018/12/24 15:49.
 */
public class ParseMysql implements Parser {

    private Predicate isEmpty = (x) -> {
        if (x == null)
            return true;
        if (x instanceof List)
            return ((List) x).isEmpty();
        if (x instanceof String)
            return ((String) x).isEmpty();
        if (x instanceof Map)
            return ((Map) x).isEmpty();
        if (x instanceof Collection)
            return ((Collection) x).isEmpty();
        return false;
    };

    Predicate<Kv<String, MetaTable>> sameDbFun = (kv) -> {
        String dbPlatId = null;
        for (MetaTable metaTable : kv.values()) {
            if (dbPlatId == null) {
                dbPlatId = metaTable.getDbPlatId();
            } else if (!dbPlatId.equals(metaTable.getDbPlatId())) {
                return false;
            }
        }
        return true;
    };

    @Override
    public String[] parse(FBean fBean) {
        MetaService metaService = MetaKit.getMetaService(fBean.getName(), fBean.getPlatToken());

        Kv<String, MetaTable> tables = MetaKit.getMetaTables(metaService, false);//所有的关联表信息
        MetaTable metaTable = tables.get(metaService.getTable());//基础元数据
        List<Map<String, String>> shows = metaService.getShows();//查询的属性-列表
        List<Map<String, String>> exports = metaService.getExports();//查询的属性-导出

        List<String> _filters = fBean.getFilters().stream().map(Filter::getCol).collect(Collectors.toList());
        List<MetaLink> links = MetaKit.getMetaLinks(
                metaService.getTable(),
                shows.stream().map(x -> x.get("col")).collect(Collectors.toList()),
                _filters
        );
        //查询条件
        List<Filter> filters = fBean.getFilters();
        Limit limit = fBean.getLimit();
        List<Order> orders = fBean.getOrders();
        //Map<String, List<Filter>> filterMap = filters.stream().collect(Collectors.groupingBy(x -> x.getCol().split("[.]")[0]));
        //Map<String, List<String>> showMap = shows.stream().collect(Collectors.groupingBy(x -> x.split("[.]")[0]));


        //判断是否为同库
        if (sameDbFun.test(tables) || true) {
            // where 1=1 and xx=xx
            StringBuffer bufWhere = new StringBuffer();
            if (!isEmpty.test(filters)) {
                bufWhere.append(Filter.filter(filters, DbType.MYSQL));
            }

            //select a.x, b.y, c.z
            StringBuffer bufSelect = new StringBuffer();
            bufSelect.append("select ");
            if ("export".equals(fBean.getType()) && !isEmpty.test(exports)) {
                exports.forEach(x -> {
                    bufSelect.append(x.get("col")).append(" as ").append("'").append(x.get("col")).append("',");
                });
                bufSelect.deleteCharAt(bufSelect.length() - 1);
            }
            else if ("list".equals(fBean.getType()) && !isEmpty.test(shows)) {
                shows.forEach(x -> {
                    bufSelect.append(x.get("col")).append(" as ").append("'").append(x.get("col")).append("',");
                });
                bufSelect.deleteCharAt(bufSelect.length() - 1);
            } else {
                bufSelect.append("*");
            }

            //from
            StringBuilder bufFrom = new StringBuilder();
            bufFrom.append(" from ").append(metaTable.getCatalog()).append(".`").append(metaTable.getName()).append("` ").append(metaTable.getAlias());
            //left join
            if (!isEmpty.test(links)) {
                links.forEach(x -> {
                    MetaTable rightTable = tables.get(metaTable.getAlias().equals(x.getTables()[0]) ? x.getTables()[1] : x.getTables()[0]);
                    if (rightTable != null) {
                        bufFrom.append(" left join ").append(rightTable.getCatalog()).append(".").append(rightTable.getName()).append(" ").append(rightTable.getAlias()).append(" on ");
                        int tag = bufFrom.length();
                        x.getLink().forEach((k, v) -> {
                            if (bufFrom.length() > tag) {
                                bufFrom.append(" and ");
                            }
                            bufFrom.append(k).append("=").append(v);
                        });
                    }
                });
            }

            StringBuffer bufOth = new StringBuffer();
            //order by
            if (!isEmpty.test(orders)) {
                bufOth.append(" ").append(Order.order(orders, DbType.MYSQL));
            }
            //limit
            bufOth.append(" ").append(limit.limit());

            return new String[]{
                    "select count(1) " + bufFrom + bufWhere,
                    "" + bufSelect + bufFrom + bufWhere + bufOth
            };
        }

        return null;
    }
}
