package com.njcn.event.influxdb;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.njcn.influx.utils.InfluxDbUtils;
import org.influxdb.InfluxDBMapperException;
import org.influxdb.dto.QueryResult;
import org.influxdb.impl.InfluxDBResultMapper;
import org.influxdb.querybuilder.SelectQueryImpl;
import org.influxdb.querybuilder.SelectionQueryImpl;
import org.influxdb.querybuilder.WhereNested;
import org.influxdb.querybuilder.WhereQueryImpl;
import org.influxdb.querybuilder.clauses.Clause;

import java.util.ArrayList;
import java.util.List;

import static org.influxdb.querybuilder.BuiltQuery.QueryBuilder.*;

/**
 * 查询抽象
 *
 * @author : zhaojun
 * @version : 1.0.0
 * @date : 2022年07月04日 18:36
 */
public abstract class QueryBuilder {

    /* 查询工具类 */
    private final InfluxDbUtils influxDbUtils;
    private final InfluxDBResultMapper resultMapper = new InfluxDBResultMapper();

    protected QueryBuilder(InfluxDbUtils influxDbUtils) {
        this.influxDbUtils = influxDbUtils;
    }

    /**
     * 数据转换
     *
     * @param queryResult 查询结果
     * @param clazz       泛型
     * @param <T>         泛型T
     * @return 查询结果映射
     * @throws InfluxDBMapperException 异常
     */
    public <T> List<T> toPOJO(final QueryResult queryResult, final Class<T> clazz) throws InfluxDBMapperException {
        return resultMapper.toPOJO(queryResult, clazz);
    }

    /**
     * 查询方法
     *
     * @param command sql
     * @return 查询结果
     */
    public QueryResult query(String command) {
        return influxDbUtils.query(command);
    }

    /**
     * select语句拼接查询字段
     *
     * @param columnNames 查询字段
     * @see SelectionQueryImpl
     */
    public SelectionQueryImpl selectAppendColumnNames(List<String> columnNames) {
        SelectionQueryImpl selectionQuery = select();
        for (String columnName : columnNames) {
            selectionQuery.column(columnName);
        }
        return selectionQuery;
    }

    /**
     * Count语句拼接查询字段
     *
     * @param columnNames 查询字段
     * @see SelectionQueryImpl
     */
    public SelectionQueryImpl countAppendColumnNames(List<String> columnNames) {
        SelectionQueryImpl selectionQuery = select();
        for (String columnName : columnNames) {
            selectionQuery.count(columnName);
        }
        return selectionQuery;
    }

    /**
     * 组装sql语句,包括or语句和and语句
     *
     * @param or  or条件
     * @param and and条件
     * @return 查询结果
     * @see SelectionQueryImpl
     */
    public QueryResult getQueryResult(List<Clause> or, List<Clause> and, SelectQueryImpl selectQuery) {
        WhereQueryImpl<SelectQueryImpl> where = selectQuery.where();
        whereAndNested(where, or);
        appendWhereOther(where, and);
        return query(selectQuery.getCommand());
    }

    /**
     * 组装sql语句,包括or语句和and语句添加对多个or语句支持
     *
     * @param or  or条件
     * @param and and条件
     * @return 查询结果
     * @see SelectionQueryImpl
     */
    public QueryResult getQueryResultUp(List<List<Clause>> or, List<Clause> and, SelectQueryImpl selectQuery) {
        WhereQueryImpl<SelectQueryImpl> where = selectQuery.where();
        for(List<Clause> item: or){
            whereAndNested(where, item);
        }
        appendWhereOther(where, and);
        return query(selectQuery.getCommand());
    }

    /**
     * 拼接or条件
     *
     * @param clauses or条件
     * @see WhereQueryImpl
     */
    public void whereAndNested(WhereQueryImpl<SelectQueryImpl> whereQuery, List<Clause> clauses) {
        WhereNested<WhereQueryImpl<SelectQueryImpl>> andNested = whereQuery.andNested();
        if (CollUtil.isNotEmpty(clauses)) {
            for (Clause clause : clauses) {
                andNested.or(clause);
            }
            andNested.close();
        }
    }

    /**
     * 拼接and条件
     *
     * @param clauses and条件
     * @see WhereQueryImpl
     */
    public void appendWhereOther(WhereQueryImpl<SelectQueryImpl> where, List<Clause> clauses) {
        if (CollUtil.isNotEmpty(clauses)) {
            for (Clause clause : clauses) {
                where.and(clause);
            }
        }
        where.tz("Asia/Shanghai");
    }

    /**
     * time and条件
     *
     * @param gteTime 开始时间
     * @param lteTime 结束时间
     * @return time and条件
     */
    public static List<Clause> timeAnd(String gteTime, String lteTime) {
        List<Clause> clauses = new ArrayList<>(15);
        clauses.add(gte("time", gteTime));
        clauses.add(lte("time", lteTime));
        return clauses;
    }

    /**
     * 格式成查询开始时间段
     *
     * @param time 时间
     * @return yyyy-MM-dd 00:00:00
     */
    public static String beginOfDay(String time) {
        DateTime date = DateUtil.parse(time);
        DateTime dateTime = DateUtil.beginOfDay(date);
        return DateUtil.formatDateTime(dateTime);
    }

    /**
     * 格式成查询结束时间段
     *
     * @param time 时间
     * @return yyyy-MM-dd 23:59:59
     */
    public static String endOfDay(String time) {
        DateTime date = DateUtil.parse(time);
        DateTime dateTime = DateUtil.endOfDay(date);
        return DateUtil.formatDateTime(dateTime);
    }
}
