package com.purui.prims.headless.core.translator.calcite.sql;

import com.purui.prims.headless.core.translator.calcite.s2sql.DataSource;
import lombok.Data;
import org.apache.calcite.sql.SqlBasicCall;
import org.apache.calcite.sql.SqlIdentifier;
import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.SqlNodeList;
import org.apache.calcite.sql.SqlSelect;
import org.apache.calcite.sql.parser.SqlParserPos;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 单表查询模型
 */
@Data
public class TableView {

    private List<SqlNode> filter = new ArrayList<>();
    private List<SqlNode> dimension = new ArrayList<>();
    private List<SqlNode> measure = new ArrayList<>();
    private SqlNodeList order;
    private SqlNode fetch;
    private SqlNode offset;
    private SqlNode table;

    private String alias;
    private List<String> primary;
    private DataSource dataSource;

    public SqlNode build() {
        // 按照维度和指标排序
        List<SqlNode> measureList = new ArrayList<>();
        measureList.addAll(dimension);
        measureList.addAll(measure);

        // 去重
        Set<String> columnNames = new HashSet<>();
        measureList.removeIf(node -> {
            if (node instanceof SqlIdentifier) {
                SqlIdentifier identifier = (SqlIdentifier) node;
                String columnName = identifier.getSimple();
                if (columnNames.contains(columnName)) {
                    return true;
                } else {
                    columnNames.add(columnName);
                    return false;
                }
            }
            return false;
        });

        measure = measureList;
        SqlNodeList dimensionNodeList = null;
        if (dimension.size() > 0) {
            dimensionNodeList = new SqlNodeList(getGroup(dimension), SqlParserPos.ZERO);
        }
        SqlNodeList filterNodeList = null;
        if (filter.size() > 0) {
            filterNodeList = new SqlNodeList(filter, SqlParserPos.ZERO);
        }
        return new SqlSelect(SqlParserPos.ZERO, null, new SqlNodeList(measureList, SqlParserPos.ZERO), table,
            filterNodeList, dimensionNodeList, null, null, null, order, offset, fetch, null);
    }

    public boolean containsNode(SqlNode node, Set<String> fields) {
        if (node instanceof SqlIdentifier) {
            SqlIdentifier identifier = (SqlIdentifier) node;
            if (fields.contains(identifier.getSimple())) {
                return true;
            }
        }
        return false;
    }

    public boolean containsNode(SqlNode node, String column) {
        if (node instanceof SqlIdentifier) {
            SqlIdentifier identifier = (SqlIdentifier) node;
            if (column.equalsIgnoreCase(identifier.getSimple())) {
                return true;
            }
        }
        return false;
    }

    private List<SqlNode> getGroup(List<SqlNode> sqlNodeList) {
        return sqlNodeList.stream()
                          .map(s -> (s.getKind().equals(SqlKind.AS) ? ((SqlBasicCall) s).getOperandList().get(0) : s))
                          .collect(
                              Collectors.toList());
    }

}
