package ru.yandex.webmaster3.storage.recommendedquery.dao;

import lombok.extern.slf4j.Slf4j;

import com.datastax.driver.core.exceptions.QueryExecutionException;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import org.joda.time.DateTime;
import org.springframework.stereotype.Repository;
import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.storage.util.ydb.AbstractYDao;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.DataMapper;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.Field;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.Fields;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.ValueDataMapper;

import ru.yandex.webmaster3.storage.util.ydb.query.Statement;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;

import static java.util.stream.Collectors.toList;

@Slf4j
@Repository
public class HostsWithOpenedRecommendedYDao extends AbstractYDao {

    public HostsWithOpenedRecommendedYDao() {
        super(PREFIX_QUERIES, "hosts_with_opened_recommended");
    }

    public void insertHost(WebmasterHostId hostId, DateTime openDate, Long userId) {
        upsert(
                F.HOST_ID.value(hostId),
                F.OPEN_DATE.value(openDate),
                F.USER_ID.value(userId)
        ).execute();
    }

    public Pair<WebmasterHostId, DateTime> getOpenDate(WebmasterHostId hostId) {
        return select(DataMapper.create(F.HOST_ID, F.OPEN_DATE, Pair::of))
                .where(F.HOST_ID.eq(hostId))
                .queryOne();
    }

    public void forEachHost(Consumer<Triple<WebmasterHostId, DateTime, Long>> consumer) {
        streamReader(DataMapper.create(F.HOST_ID, F.OPEN_DATE, F.USER_ID, Triple::of), consumer);
    }

    public void forEach(Consumer<WebmasterHostId> consumer) {
        streamReader(F.HOST_ID, consumer);
    }

    public void delete(List<WebmasterHostId> hostIds) {
        List<List<WebmasterHostId>> batches = Lists.partition(hostIds, 1000);
        for (var batch : batches) {
            delete().where(F.HOST_ID.in(new ArrayList<>(batch))).execute();
        }
    }

    public void deleteForUser(long userId) {
        var sel = select(PK_MAPPER).secondaryIndex("user_id_index").where(F.USER_ID.eq(userId)).getStatement();
        delete().on(sel).execute();
    }

    public void batchInsert(List<Triple<WebmasterHostId, DateTime, Long>> items) {
        batchInsert(VALUE_MAPPER, items).execute();
    }

    private static final ValueDataMapper<Triple<WebmasterHostId, DateTime, Long>> VALUE_MAPPER = ValueDataMapper.create2(
        Pair.of(F.HOST_ID, Triple::getLeft),
        Pair.of(F.OPEN_DATE, Triple::getMiddle),
        Pair.of(F.USER_ID, Triple::getRight)
    );

    private static final DataMapper<WebmasterHostId> PK_MAPPER = DataMapper.create(F.HOST_ID, id -> id);

    private static final class F {
        static final Field<WebmasterHostId> HOST_ID = Fields.hostIdField("host_id");
        static final Field<DateTime> OPEN_DATE = Fields.jodaDateTimeField("open_date").makeOptional();
        static final Field<Long> USER_ID = Fields.longField("user_id").makeOptional();
    }
}
