package ru.yandex.webmaster3.worker.niche2;

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

import com.google.common.collect.ImmutableMap;

import ru.yandex.webmaster3.core.worker.task.PeriodicTaskType;
import ru.yandex.webmaster3.storage.clickhouse.TableType;
import ru.yandex.webmaster3.storage.niche2.Niche2QueriesCHDao;
import ru.yandex.webmaster3.storage.niche2.Niche2QueriesCHDao.F;
import ru.yandex.webmaster3.storage.util.clickhouse2.AbstractClickhouseDao;
import ru.yandex.webmaster3.storage.util.clickhouse2.CHField;
import ru.yandex.webmaster3.storage.util.clickhouse2.CHPrimitiveType;
import ru.yandex.webmaster3.storage.util.clickhouse2.CHTable;
import ru.yandex.webmaster3.storage.yql.YqlFunctions;
import ru.yandex.webmaster3.storage.yql.YqlQueryBuilder;
import ru.yandex.webmaster3.storage.ytimport.YtClickhouseDataLoad;
import ru.yandex.webmaster3.storage.ytimport.YtClickhouseDataLoadType;
import ru.yandex.webmaster3.worker.TaskSchedule;
import ru.yandex.webmaster3.worker.turbo.AbstractYqlPrepareImportTask;

public class ImportNicheQueriesReportTask extends AbstractYqlPrepareImportTask {
    private static final int LINES_COUNT = 512;
    private static final String TABLE_NAME = Niche2QueriesCHDao.TABLE_NAME;

    private static final CHTable TABLE = CHTable.builder()
            .database(AbstractClickhouseDao.DB_WEBMASTER3_NICHE)
            .name(TABLE_NAME + "_%s")
            .partitionBy("cityHash64(domain) % 16")
            .sharded(true)
            .keyField(F.DOMAIN, CHPrimitiveType.String)
            .keyField(F.GROUP_NAME, CHPrimitiveType.String)
            .keyField(F.QUERY, CHPrimitiveType.String)
            .field(F.SHOWS, CHPrimitiveType.Int64)
            .field(F.AVERAGE_POSITION, CHPrimitiveType.Int64)
            .field(F.CLICKS, CHPrimitiveType.Int64)
            .field(F.URL, CHPrimitiveType.String)
            .field(F.PROBLEMS, CHPrimitiveType.String)
            .field(F.SIMILAR_URLS, CHPrimitiveType.String)
            .field(F.WEIGHT, CHPrimitiveType.Float64)
            .build();

    private static final Map<String, String> SOURCE_EXPRESSIONS = new ImmutableMap.Builder<String, String>()
            .put(F.DOMAIN, "Domain")
            .put(F.GROUP_NAME, "$escape(GroupId)")
            .put(F.QUERY, "$escape(Query)")
            .put(F.SHOWS, "cast(nvl(AskedCount, 0) as String)")
            .put(F.AVERAGE_POSITION, "cast(nvl(AveragePosition, 0) as String)")
            .put(F.CLICKS, "cast(nvl(Clicks, 0) as String)")
            .put(F.URL, "$escape(nvl(LandingPage, ''))")
            .put(F.PROBLEMS, "$escape(nvl(cast(Yson::SerializeJson(Yson::From(LandingProblems)) as String), 'null'))")
            .put(F.SIMILAR_URLS, "$escape(nvl(cast(Yson::SerializeJson(Yson::From(ListTake(SimilarPages, 10))) as String), 'null'))")
            .put(F.WEIGHT, "cast(nvl(Weight, 0.0) as String)")
            .build();

    @Override
    protected YtClickhouseDataLoad init(YtClickhouseDataLoad imprt) throws Exception {
        return initByUpdateDate(imprt);
    }

    @Override
    protected int getShardsCount() {
        return clickhouseServer.getShardsCount();
    }

    @Override
    protected YqlQueryBuilder prepareIntermediateTable(YtClickhouseDataLoad imprt) {
        String fields = getTable().getFields().stream().map(CHField::getName).map(SOURCE_EXPRESSIONS::get)
                .collect(Collectors.joining(" || '\\t' || ", "(", " || '\\n')"));

        return YqlQueryBuilder.newBuilder()
                .cluster(tablePath)
                .appendFDefinition(YqlFunctions.ESCAPE)
                .appendText("PRAGMA yt.MaxRowWeight = '128M';\n")
                .appendText("PRAGMA yt.DefaultMemoryLimit = '8G';\n\n")
                .appendText("INSERT INTO " + INTERMEDIATE_TABLE)
                .appendText("SELECT ShardId, RowId, Compress::Gzip(String::JoinFromList(AGGREGATE_LIST(data), ''), 6) as data FROM (\n")
                .appendText("SELECT (Digest::Fnv64(Domain) % " + getShardsCount() + ") as ShardId,")
                .appendText("((Digest::Fnv64(Domain || GroupId || Query) / " + getShardsCount() + ") % " + LINES_COUNT + ") as RowId,")
                .appendText(fields).appendText(" as data\n")
                .appendText("FROM")
                .appendTable(imprt.getSourceTable())
                .appendText(") \n GROUP BY ShardId, RowId;")
                .appendText("COMMIT;\n\n");
    }

    @Override
    protected CHTable getTable() {
        return TABLE;
    }

    @Override
    protected TableType getTableType() {
        return TableType.NICHE2_QUERY_REPORT;
    }

    @Override
    protected YtClickhouseDataLoadType getImportType() {
        return YtClickhouseDataLoadType.NICHE2_QUERY_REPORT;
    }

    @Override
    public TaskSchedule getSchedule() {
        return TaskSchedule.startByCron("0 */5 * * * *");
    }


    @Override
    public PeriodicTaskType getType() {
        return PeriodicTaskType.IMPORT_NICHE2_QUERIES_REPORT;
    }
}
