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

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

import lombok.Value;
import org.apache.commons.lang3.tuple.Pair;
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;

/**
 * Created by Oleg Bazdyrev on 04/10/2018.
 */
@Repository
public class HostAchievementsRivalsYDao extends AbstractYDao {

    private static final String TABLE_NAME = "host_achievements_rivals";

    public HostAchievementsRivalsYDao() {
        super(PREFIX_WEBMASTER3, TABLE_NAME);
    }

    public void addRival(WebmasterHostId hostId, String rival) {
        // костыли, себя считаем добавленным по умолчанию
        if (hostId.getPunycodeHostname().equals(rival)) {
            delete().where(F.HOST_ID.eq(hostId)).and(F.RIVAL.eq(rival)).execute();
        } else {
            upsert(F.HOST_ID.value(hostId), F.RIVAL.value(rival)).execute();
        }
    }

    public void removeRival(WebmasterHostId hostId, String rival) {
        if (hostId.getPunycodeHostname().equals(rival)) {
            upsert(F.HOST_ID.value(hostId), F.RIVAL.value(rival)).execute();
        } else {
            delete().where(F.HOST_ID.eq(hostId)).and(F.RIVAL.eq(rival)).execute();
        }
    }

    public List<String> getRivalsFiltered(WebmasterHostId hostId) {
        List<String> result = getRivalsNoFilter(hostId);
        String thisHostName = hostId.getPunycodeHostname();
        int thisHostIndex = result.indexOf(thisHostName);
        if (thisHostIndex == -1) {
            // Если записи про себя как конкурента нет в таблице, то добавляем к результату,
            // Делается это для того, чтобы при первом заходе не страницу пользователь увидел
            // свой сайт в списке конкурентов для сравнения.
            result.add(0, thisHostName);
        } else {
            // Запись про себя как конкурента есть в таблице. Это, на самом деле, означает что
            // пользователь когда то удалил эту запись в интерфейсе, поэтому удаляем из результата.
            result.remove(thisHostIndex);
        }
        return result;
    }

    public void forEach(Consumer<RowRecord> consumer) {
        streamReader(MAPPER, consumer);
    }

    public void batchInsert(List<RowRecord> items) {
        batchInsert(VALUE_MAPPER, items).execute();
    }

    private List<String> getRivalsNoFilter(WebmasterHostId hostId) {
        return select(F.RIVAL).where(F.HOST_ID.eq(hostId)).queryForList();
    }

    private interface F {
        Field<WebmasterHostId> HOST_ID = Fields.hostIdField("host_id");
        Field<String> RIVAL = Fields.stringField("rival");
    }

    private static final ValueDataMapper<RowRecord> VALUE_MAPPER = ValueDataMapper.create2(
            Pair.of(F.HOST_ID, RowRecord::getHostId),
            Pair.of(F.RIVAL, RowRecord::getRival)
    );

    private static final DataMapper<RowRecord> MAPPER = DataMapper.create(
            F.HOST_ID, F.RIVAL, RowRecord::new);

    @Value
    public static class RowRecord {
        WebmasterHostId hostId;
        String rival;
    }
}
