package ru.yandex.webmaster3.worker.sitetree;

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

import com.google.common.collect.ImmutableMap;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.text.StrSubstitutor;
import org.springframework.beans.factory.annotation.Autowired;

import ru.yandex.webmaster3.storage.clickhouse.TableType;
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.util.yt.YtPath;
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;

import static ru.yandex.webmaster3.storage.clickhouse.TableType.HOSTS;
import static ru.yandex.webmaster3.storage.util.clickhouse2.AbstractClickhouseDao.DB_WEBMASTER3;


/**
 * @author kravchenko99
 * @date 4/21/21
 */


@Slf4j
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class ImportWebmasterHostsToClickhouseTask extends AbstractYqlPrepareImportTask {


    private static final String HOST_ID = "host_id";
    private static final String DATE = "date";
    private static final String PREFIX_TABLE_NAME = "hosts_";
    private static final String DATABASE = DB_WEBMASTER3;
    public static final CHTable TABLE = CHTable.builder()
            .database(DATABASE)
            .name(PREFIX_TABLE_NAME + "%s")
            .sharded(false)
            .keyDateField(DATE)
            .keyField(HOST_ID, CHPrimitiveType.String)
            .build();

    private static final int LINES_COUNT = 128;

    private static final Map<String, String> SOURCE_EXPRESSIONS = new ImmutableMap.Builder<String, String>()
            .put(HOST_ID, "$url2HostId(`Host`)")
            .build();

    @Override
    protected int getShardsCount() {
        return 1;
    }


    @Override
    protected YqlQueryBuilder prepareIntermediateTable(YtClickhouseDataLoad imprt) {
        final String dateString = IN_YQL_QUERY_DATE_FORMATTER.print(imprt.getDateTo());
        final YtPath sourceTable = imprt.getSourceTable();
        final String fields = getTable().getFields().stream()
                .map(CHField::getName)
                .filter(chField -> !chField.equals(DATE))
                .map(SOURCE_EXPRESSIONS::get)
                .collect(Collectors.joining(" || '\\t' || ", "('" + dateString + "'|| '\\t' || ", " || '\\n')"));

        final Map<String, String> values = Map.of(
                "allHostsWebmasterTable", sourceTable.toYqlPath(),
                "INTERMEDIATE_TABLE", INTERMEDIATE_TABLE,
                "LINES_COUNT", String.valueOf(LINES_COUNT),
                "SHARDS_COUNT", String.valueOf(getShardsCount()),
                "fields", fields,
                "KEY_FOR_SHARD", "Digest::Fnv64($url2HostId(`Host`))"
        );
        StrSubstitutor sub = new StrSubstitutor(values);

        String template = "PRAGMA yt.MaxRowWeight = '128M';\n" +
                "PRAGMA yt.InferSchema = '1';\n" +
                "INSERT INTO ${INTERMEDIATE_TABLE} " +
                "SELECT ShardId, RowId, Compress::Gzip(String::JoinFromList(AGGREGATE_LIST(data), ''), 6) as data " +
                "FROM (\n" +
                "SELECT ${KEY_FOR_SHARD} % ${SHARDS_COUNT} as ShardId, (" +
                "${KEY_FOR_SHARD} / ${SHARDS_COUNT}) % ${LINES_COUNT}  as RowId, ${fields} as data " +
                "FROM ${allHostsWebmasterTable} as allHostsWebmasterTable) \n" +
                "GROUP BY ShardId, RowId;\n " +
                "COMMIT;\n\n";

        String query = sub.replace(template);

        return YqlQueryBuilder.newBuilder()
                .cluster(sourceTable)
                .appendFDefinition(YqlFunctions.URL_2_HOST_ID)
                .appendText(query);
    }

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

    @Override
    protected TableType getTableType() {
        return HOSTS;
    }

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


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


}
