package ru.yandex.webmaster3.storage.clickhouse.system.dao;

import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Required;
import ru.yandex.webmaster3.storage.util.clickhouse2.AbstractClickhouseDao;
import ru.yandex.webmaster3.storage.util.clickhouse2.ClickhouseException;
import ru.yandex.webmaster3.storage.util.clickhouse2.ClickhouseHost;
import ru.yandex.webmaster3.storage.util.clickhouse2.ClickhouseQueryContext;
import ru.yandex.webmaster3.storage.util.clickhouse2.query.GroupBy;
import ru.yandex.webmaster3.storage.util.clickhouse2.query.QueryBuilder;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author Oleg Bazdyrev
 */
public class ClickhouseSystemPartsCHDao extends AbstractClickhouseDao {
    private static final String TABLE_NAME = "system.parts";

    private ClickhouseSystemTablesCHDao clickhouseSystemTablesCHDao;

    public void checkTablesNotEmpty(String database, String prefix) throws ClickhouseException {
        Set<String> tables = clickhouseSystemTablesCHDao.getTableNamesForPrefix(database, prefix);
        checkTablesNotEmpty(database, tables, Integer.MAX_VALUE);
    }

    public void checkTablesNotEmpty(String database, Set<String> tables, int maxShard) throws ClickhouseException {
        if (tables.isEmpty()) {
            return;
        }
        GroupBy st = QueryBuilder.select(F.TABLE, F.SUM_BYTES)
                .from(TABLE_NAME)
                .where(QueryBuilder.in(F.TABLE, tables))
                .groupBy(F.TABLE);
        List<ClickhouseHost> hosts = getClickhouseServer().getHosts().stream()
                .filter(host -> host.getShard() < maxShard).collect(Collectors.toList());
        for (ClickhouseHost host : hosts) {
            ClickhouseQueryContext.Builder context = ClickhouseQueryContext.useDefaults().setHost(host);
            Map<String, Long> tableSizes = getClickhouseServer().queryAll(context, st.toString(),
                    chRow -> Pair.of(chRow.getString(F.TABLE), chRow.getLongUnsafe(F.SUM_BYTES)))
                    .stream().collect(Collectors.toMap(Pair::getLeft, Pair::getRight));
            // проверим, что все таблицы есть
            for (String table : tables) {
                Long size = tableSizes.get(table);
                if (size == null || size <= 0L) {
                    throw new RuntimeException("Table " + database + "." + table + " on host " + host + " is empty");
                }
            }
        }
    }

    @Required
    public void setClickhouseSystemTablesCHDao(ClickhouseSystemTablesCHDao clickhouseSystemTablesCHDao) {
        this.clickhouseSystemTablesCHDao = clickhouseSystemTablesCHDao;
    }

    private interface F {
        String DATABASE = "database";
        String TABLE = "table";
        String BYTES = "bytes";
        String SUM_BYTES = "sum(bytes)";
        String ENGINE = "engine";
    }
}
