package net.tccn.base;

import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.select.*;
import net.tccn.base.dbq.jdbc.api.DbSource;

import java.lang.reflect.Array;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Created by liangxianyou at 2019/3/19 18:01.
 */
public class Utils {

    /**
     * 将集合数组合并到一个Set<T> 集合中
     *
     * @param <T>     泛型
     * @param streams 集合数组
     * @return
     */
    public static <T> Stream<T> concat(Stream<T>... streams) {
        Stream<T> stream = Stream.empty();
        for (int i = 0; i < streams.length; i++) {
            stream = Stream.concat(stream, streams[i]);
        }
        return stream;
    }

    /**
     * 将字符串第一个字母转大写
     *
     * @param str 待转换字符串
     * @return
     */
    public static String toUpperCaseFirst(String str) {
        Objects.requireNonNull(str);
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }

    /**
     * 转化集合为数组，带泛型支持
     *
     * @param values 集合
     * @param <T>    泛型
     * @return
     */
    public static <T> T[] toArray(Collection<T> values) {
        if (values == null || values.size() == 0)
            throw new UnsupportedOperationException("Not supported yet.");
        Class<?> clazz = null;
        for (T entity : values) {
            clazz = entity.getClass();
            break;
        }
        return values.toArray((T[]) Array.newInstance(clazz, values.size()));
    }

    /**
     * 转化集合为数组，带泛型支持
     *
     * @param values 集合
     * @param <T>    泛型
     * @return
     */
    public static <T> T[] toArray(Stream<T> values) {
        if (values == null || values.count() == 0)
            throw new UnsupportedOperationException("Not supported yet.");

        List<T> list = values.collect(Collectors.toList());
        return toArray(list);
    }

    /**
     * @param type 待加载的class 类型
     * @param name class 的实现名称
     * @param <T>  泛型<T>
     * @return
     */
    public static <T extends DbSource> T getDbSource(Class<T> type, String name) {
        ServiceLoader<T> loader = ServiceLoader.load(type);
        Iterator<T> iterator = loader.iterator();

        if (iterator.hasNext()) {
            T t = iterator.next();
            if (name.equalsIgnoreCase(t.getType())) {
                return t;
            }
        }

        /*if ("mysql".equalsIgnoreCase(name)) {
            return (T) new DbSourceMysql();
        }*/

        return null;
    }

    public static boolean isEmpty(Object obj) {
        if (obj == null)
            return true;
        if (obj instanceof List)
            return ((List) obj).isEmpty();
        if (obj instanceof String)
            return ((String) obj).isEmpty();
        if (obj instanceof Map)
            return ((Map) obj).isEmpty();
        if (obj instanceof Collection)
            return ((Collection) obj).isEmpty();
        if (obj instanceof Object[])
            return ((Object[]) obj).length == 0;
        return false;
    }

    public static String fmt36(int n) {
        return Integer.toString(n, 36);
    }

    public static String fmt36(long n) {
        return Long.toString(n, 36);
    }

    public static <T, V> Map<T, V> toMap(Collection<V> list, Function<V, T> fun) {
        Map<T, V> map = new HashMap<>(list.size());
        for (V v : list) {
            if (v == null) {
                continue;
            }
            map.put(fun.apply(v), v);
        }
        return map;
    }

    public static <T, V, T2> Map<T, T2> toMap(Collection<V> list, Function<V, T> fun, Function<V, T2> fun2) {
        Map<T, T2> map = new HashMap<>(list.size());
        for (V v : list) {
            if (v == null) {
                continue;
            }
            map.put(fun.apply(v), fun2.apply(v));
        }
        return map;
    }

    public static <T, V> List<V> toList(Collection<T> list, Function<T, V> fun) {
        if (list == null || list.isEmpty()) {
            return new ArrayList<>();
        }
        List<V> list1 = new ArrayList<>();
        list.forEach(x -> list1.add(fun.apply(x)));
        return list1;
    }

    public static <T, V> Set<V> toSet(Collection<T> list, Function<T, V> fun) {
        if (list == null || list.isEmpty()) {
            return new HashSet<>();
        }
        Set<V> set = new HashSet<>(list.size());
        list.forEach(x -> set.add(fun.apply(x)));
        return set;
    }

    public static <T> List<T> filter(Collection<T> list, Predicate<T> predicate) {
        if (list == null || list.isEmpty()) {
            return new ArrayList<>();
        }
        List<T> list1 = new ArrayList<>(list.size());
        list.forEach(x -> {
            if (!predicate.test(x)) {
                return;
            }

            list1.add(x);
        });

        return list1;
    }

    public static <T, V> List<V> filterToList(Collection<T> list, Predicate<T> predicate, Function<T, V> fun) {
        if (list == null || list.isEmpty()) {
            return new ArrayList<>();
        }
        List<V> list1 = new ArrayList<>(list.size());

        list.forEach(x -> {
            if (!predicate.test(x)) {
                return;
            }

            list1.add(fun.apply(x));
        });

        return list1;
    }

    public static <T, V> Map<V, List<T>> group(Collection<T> list, Function<T, V> fun) {
        if (list == null || list.isEmpty()) {
            return new HashMap<>();
        }
        return list.stream().collect(Collectors.groupingBy(fun));
    }

    public static <T, V, K> Map<V, List<K>> group(Collection<T> list, Function<T, V> fun, Function<T, K> fun2) {
        if (list == null || list.isEmpty()) {
            return new HashMap<>();
        }
        Map<V, List<T>> group = group(list, fun);
        Map<V, List<K>> _group = new HashMap<>();
        group.forEach((k, v) -> _group.put(k, toList(v, fun2)));
        return _group;
    }

    public static String parserSql(String originalSql) {
        try {
            Select select = (Select) CCJSqlParserUtil.parse(originalSql);

            // 如果未设置分页，设置默认分页 99
            if (select.getLimit() == null) {
                Limit limit = new Limit().withRowCount(new LongValue(10));
                select.setLimit(limit);

                originalSql = select.toString();
            }

            return originalSql;
        } catch (JSQLParserException e) {
            throw new RuntimeException(e);
        }
    }

    public static String parserCountSql(String originalSql) {
        String sqlCount = "SELECT COUNT(1)";
        try {
            Select select = (Select) CCJSqlParserUtil.parse(originalSql);
            PlainSelect plainSelect = select.getPlainSelect();

            FromItem fromItem = plainSelect.getFromItem();
            List<Join> joins = plainSelect.getJoins();
            Expression where = plainSelect.getWhere();
            GroupByElement group = plainSelect.getGroupBy();

            if (fromItem == null) {
                return null;
            }

            sqlCount += " FROM " + fromItem;
            if (joins != null) {
                for (Join join : joins) {
                    sqlCount += " " + join;
                }
            }
            if (!Utils.isEmpty(where)) {
                sqlCount += " WHERE " + where;
            }
            if (!Utils.isEmpty(group)) {
                sqlCount += " " + group;

                sqlCount = "SELECT COUNT(1) FROM (" + sqlCount + ") _";
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return sqlCount;
    }

}
