package ru.yandex.webmaster3.storage.yql;

import ru.yandex.webmaster3.storage.util.yt.YtPath;

import java.util.LinkedHashSet;

/**
 * @author avhaliullin
 */
public class YqlQueryBuilder {
    private String transactionId;
    private String cluster;
    private StringBuilder queryBuilder = new StringBuilder();
    private InferSchemaMode inferSchemaMode;
    private final LinkedHashSet<YqlFunctionDef> functionDefinitions = new LinkedHashSet<>();

    public YqlQueryBuilder transaction(String transactionId) {
        this.transactionId = transactionId;
        return this;
    }

    public YqlQueryBuilder cluster(YtPath path) {
        return cluster(path.getCluster());
    }

    public YqlQueryBuilder cluster(String cluster) {
        this.cluster = cluster;
        return this;
    }

    public YqlQueryBuilder inferSchema(InferSchemaMode mode) {
        inferSchemaMode = mode;
        return this;
    }

    public YqlQueryBuilder appendText(String text) {
        queryBuilder.append(text).append(" ");
        return this;
    }

    public YqlQueryBuilder appendTable(YtPath table) {
        queryBuilder.append(" ");
        if (cluster == null) {
            queryBuilder.append(table.getCluster()).append(".");
        }
        queryBuilder.append("`").append(table.toYtPath()).append("` ");
        return this;
    }

    public YqlQueryBuilder appendFCall(YqlFunctionCall function) {
        functionDefinitions.add(function.getFunction());
        queryBuilder.append(function.getApplicationCode()).append(" ");
        return this;
    }

    public YqlQueryBuilder appendFDefinition(YqlFunctionDef def) {
        functionDefinitions.add(def);
        return this;
    }

    public String build() {
        StringBuilder res = new StringBuilder();
        if (transactionId != null) {
            res.append("pragma yt.ExternalTx='").append(transactionId).append("';\n");
        }
        if (inferSchemaMode != null) {
            res.append("pragma ").append(inferSchemaMode.pragmaValue).append(";\n");
        }
        if (cluster != null) {
            res.append("use ").append(cluster).append(";\n");
        }
        for (YqlFunctionDef functionDef : functionDefinitions) {
            res.append(functionDef.getFunctionDef());
        }
        res.append(queryBuilder);
        return res.toString();
    }

    public static YqlQueryBuilder newBuilder() {
        return new YqlQueryBuilder();
    }

    public enum InferSchemaMode {
        INFER("yt.InferSchema"),
        FORCE_INFER("yt.ForceInferSchema"),
        ;
        private final String pragmaValue;

        InferSchemaMode(String pragmaValue) {
            this.pragmaValue = pragmaValue;
        }
    }
}
