package ru.yandex.webmaster3.worker.turbo;

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

import com.google.common.collect.ImmutableMap;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;

import ru.yandex.webmaster3.storage.clickhouse.TableType;
import ru.yandex.webmaster3.storage.turbo.dao.TurboFeedsHistoryCHDao;
import ru.yandex.webmaster3.storage.turbo.dao.TurboFeedsHistoryCHDao.F;
import ru.yandex.webmaster3.storage.util.clickhouse2.CHField;
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;

/**
 * Created by Oleg Bazdyrev on 03/08/2020.
 */
@Slf4j
public class ImportTurboFeedsHistoryTask extends AbstractYqlPrepareImportTask {

    private static final int LINES_COUNT = 1024;
    private static final long LIMIT_MILLIS_FOR_TESTING = TimeUnit.DAYS.toMillis(7);

    private static final Map<String, String> SOURCE_EXPRESSIONS = new ImmutableMap.Builder<String, String>()
            .put(F.DATE, "$getDate(cast(`timestamp` as Uint32))")
            .put(F.FEED, "feed")
            .put(F.TIMESTAMP, "cast(`timestamp` as String)")
            .put(F.DATA, "String::ReplaceAll(cast(Yson::SerializeJson(data) as String), @@\\@@, @@\\\\@@)")
            .put(F.LAST_ACCESS, "cast(nvl(last_access, 0) as String)")
            .put(F.TYPE, "type")
            .build();

    @Value("${webmaster3.worker.turbo.feedsHistory.import.limit}")
    private boolean limitHistory;

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

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

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

        YqlQueryBuilder yqlQueryBuilder = YqlQueryBuilder.newBuilder()
                .cluster(tablePath)
                .appendFDefinition(YqlFunctions.URL_2_HOST_ID)
                .appendText("PRAGMA yt.DefaultMemoryLimit = '4G';\n")
                .appendText("PRAGMA yt.MaxRowWeight = '128M';\n")
                .appendText("$printDate = DateTime::Format('%Y-%m-%d');\n")
                .appendText("$getDate = ($ts) -> { return $printDate(AddTimezone(DateTime::FromSeconds($ts), 'Europe/Moscow')); };\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(feed) % " + getShardsCount() + ") as ShardId,")
                .appendText("((Digest::Fnv64(feed || cast(`timestamp` as String))) % " + LINES_COUNT + ") as RowId,")
                .appendText(fields).appendText("as data ")
                .appendText("FROM")
                .appendTable(imprt.getSourceTable());
        if (limitHistory) {
            yqlQueryBuilder.appendText("WHERE `timestamp` > " + (System.currentTimeMillis() - LIMIT_MILLIS_FOR_TESTING) / 1000);
        }
        yqlQueryBuilder
                .appendText(") \n GROUP BY ShardId, RowId;")
                .appendText("COMMIT;\n\n");

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

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