package ru.yandex.webmaster3.storage.importer.model.postprocess;

import java.util.stream.Collectors;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.joda.time.Duration;

import ru.yandex.webmaster3.storage.importer.model.ImportColumnDefinition;
import ru.yandex.webmaster3.storage.importer.model.ImportContext;
import ru.yandex.webmaster3.storage.importer.model.ImportDefinition;
import ru.yandex.webmaster3.storage.importer.model.ImportTask;
import ru.yandex.webmaster3.storage.util.clickhouse2.ClickhouseHost;
import ru.yandex.webmaster3.storage.util.clickhouse2.ClickhouseQueryContext;
import ru.yandex.webmaster3.storage.util.clickhouse2.MdbClickhouseServer;

/**
 * Created by Oleg Bazdyrev on 20/01/2021.
 * Мержит временную табличку в общую
 */
@Slf4j
@Value
@AllArgsConstructor(onConstructor_ = @JsonCreator)
@Builder
@JsonIgnoreProperties(ignoreUnknown = true)
public class ImportPostprocessMerge implements ImportPostprocessPolicy {

    // имя таблицы для мержа
    String tableName;
    // фильтр для чистки возможных кривых данных
    String clearFilter;

    @Override
    public ImportTask apply(ImportContext context) {
        ImportTask task = context.getTask();
        ImportDefinition definition = context.getDefinition();
        MdbClickhouseServer clickhouseServer = context.getClickhouseServer();
        // чистим данные из таблицы
        if (!Strings.isNullOrEmpty(clearFilter)) {
            // операция асинхронная, большие таймауты не нужны
            String clearQuery = "ALTER TABLE " + task.getDatabase() + "." + tableName + " ON CLUSTER " + clickhouseServer.getClusterId() +
                    " DELETE WHERE " + context.createSubstitutor(null).replace(clearFilter) + ";";
            clickhouseServer.execute(ClickhouseQueryContext.useDefaults(), clearQuery);
        }
        // копируем данные из временной заимпорченной таблицы на место
        StringBuilder insertQuery = new StringBuilder(1024);
        insertQuery.append("INSERT INTO ").append(task.getDatabase()).append(".").append(tableName).append(" ");
        String columns = "*";
        if (!CollectionUtils.isEmpty(definition.getColumns())) {
            columns = definition.getColumns().stream().map(ImportColumnDefinition::getChName) .collect(Collectors.joining(", "));
            insertQuery.append("(").append(columns).append(")");
        }
        insertQuery.append(" SELECT ").append(columns).append(" FROM ").append(task.getDatabase()).append(".").append(task.getLocalTableName());
        insertQuery.append(";");
        var chContext = ClickhouseQueryContext.useDefaults().setTimeout(Duration.standardMinutes(10L));
        for (ClickhouseHost host : clickhouseServer.getAliveHostsForEachShard()) {
            clickhouseServer.execute(chContext.setHost(host), insertQuery.toString());
        }

        return context.getTask().withNextStage().build();
    }

    @Override
    public ImportPostprocessType getType() {
        return ImportPostprocessType.MERGE;
    }

    @Override
    public void validate() {
        Preconditions.checkArgument(!Strings.isNullOrEmpty(tableName), "Table name for merge is required");
    }
}
