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

import com.purui.prims.headless.core.pojo.MetricQueryParam;
import com.purui.prims.headless.core.pojo.QueryStatement;
import com.purui.prims.headless.core.translator.QueryParser;
import com.purui.prims.headless.api.pojo.enums.AggOption;
import com.purui.prims.headless.api.pojo.enums.EngineType;
import com.purui.prims.headless.core.translator.calcite.planner.AggPlanner;
import com.purui.prims.headless.core.translator.calcite.s2sql.SemanticModel;
import com.purui.prims.headless.core.translator.calcite.schema.RuntimeOptions;
import com.purui.prims.headless.core.translator.calcite.schema.SemanticSchema;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Objects;

/**
 * the calcite parse implements
 */
@Component("CalciteQueryParser")
@Slf4j
public class CalciteQueryParser implements QueryParser {

    @Override
    public void parse(QueryStatement queryStatement, AggOption isAgg) throws Exception {
        MetricQueryParam metricReq = queryStatement.getMetricQueryParam();
        SemanticModel semanticModel = queryStatement.getSemanticModel();
        if (semanticModel == null) {
            queryStatement.setErrMsg("semanticSchema not found");
            return;
        }
        queryStatement.setMetricQueryParam(metricReq);
        SemanticSchema semanticSchema = getSemanticSchema(semanticModel, queryStatement);
        AggPlanner aggBuilder = new AggPlanner(semanticSchema);
        aggBuilder.explain(queryStatement, isAgg);
        EngineType engineType = EngineType.fromString(semanticSchema.getSemanticModel().getDatabase().getType());
        queryStatement.setSql(aggBuilder.getSql(engineType));
        queryStatement.setSourceId(aggBuilder.getSourceId());
        // 直接查询优化或加速后的数据集
        if (Objects.nonNull(queryStatement.getEnableOptimize()) && queryStatement.getEnableOptimize()
                && Objects.nonNull(queryStatement.getDataSetAlias()) && !queryStatement.getDataSetAlias().isEmpty()) {
            // 简化SQL
            String simplifySql = aggBuilder.simplify(
                    getSqlByDataSet(aggBuilder.getSql(engineType), queryStatement.getDataSetSql(),
                            queryStatement.getDataSetAlias()), engineType);
            if (Objects.nonNull(simplifySql) && !simplifySql.isEmpty()) {
                log.debug("simplifySql [{}]", simplifySql);
                queryStatement.setDataSetSimplifySql(simplifySql);
            }
        }
    }

    private SemanticSchema getSemanticSchema(SemanticModel semanticModel, QueryStatement queryStatement) {
        SemanticSchema semanticSchema = SemanticSchema.newBuilder(semanticModel.getSchemaKey()).build();
        semanticSchema.setSemanticModel(semanticModel);
        semanticSchema.setDatasource(semanticModel.getDatasourceMap());
        semanticSchema.setDimension(semanticModel.getDimensionMap());
        semanticSchema.setMetric(semanticModel.getMetrics());
        semanticSchema.setJoinRelations(semanticModel.getJoinRelations());
        semanticSchema.setRuntimeOptions(RuntimeOptions.builder().minMaxTime(queryStatement.getMinMaxTime())
                .enableOptimize(queryStatement.getEnableOptimize()).build());
        return semanticSchema;
    }

    private String getSqlByDataSet(String sql, String dataSetSql, String dataSetAlias) {
        return String.format("with %s as (%s) %s", dataSetAlias, sql, dataSetSql);
    }
}
