package ru.yandex.webmaster3.storage.turbo.dao.statistics;

import java.util.Collection;
import java.util.EnumMap;
import java.util.List;
import java.util.NavigableMap;
import java.util.TreeMap;

import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import org.joda.time.LocalDate;
import org.springframework.stereotype.Repository;

import ru.yandex.webmaster3.core.turbo.model.feed.TurboFeedType;
import ru.yandex.webmaster3.core.turbo.model.statistics.TurboDomainStatistics;
import ru.yandex.webmaster3.core.turbo.model.statistics.TurboHostStatisticsType;
import ru.yandex.webmaster3.core.turbo.model.statistics.TurboTotalStatistics;
import ru.yandex.webmaster3.core.turbo.model.statistics.TurboTotalStatistics.TurboTotalStatisticsBuilder;
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 06/02/2018.
 */
@Repository
public class TurboDomainStatisticsHistoryYDao extends AbstractYDao {

    public static final String TABLE_NAME = "turbo_domain_statistics_history";
    private static final DataMapper<Triple<LocalDate, TurboHostStatisticsType, Long>> TRIPLE_MAPPER =
            DataMapper.create(F.DATE, F.TYPE, F.VALUE, Triple::of);
    private static final DataMapper<TurboDomainStatistics> MAPPER =
            DataMapper.create(F.DOMAIN, F.SOURCE, F.FEED, F.TYPE, F.VALUE, TurboDomainStatistics::new);

    private static final ValueDataMapper<TurboDomainStatistics> VALUE_DATA_MAPPER = ValueDataMapper.create2(
            Pair.of(F.DOMAIN, TurboDomainStatistics::getDomain),
            Pair.of(F.SOURCE, TurboDomainStatistics::getSource),
            Pair.of(F.DATE, stats -> stats.getUpdateDate().toLocalDate()),
            Pair.of(F.FEED, TurboDomainStatistics::getFeed),
            Pair.of(F.TYPE, TurboDomainStatistics::getType),
            Pair.of(F.VALUE, TurboDomainStatistics::getValue)
    );

    public TurboDomainStatisticsHistoryYDao() {
        super(PREFIX_TURBO, TABLE_NAME);
    }

    public void saveStatistics(Collection<TurboDomainStatistics> statsBatch) {
        batchUpdate(VALUE_DATA_MAPPER, statsBatch).execute();
    }

    public NavigableMap<LocalDate, EnumMap<TurboHostStatisticsType, Long>> getStatistics(
            String domain, TurboFeedType source, LocalDate from, LocalDate to) {
        List<Triple<LocalDate, TurboHostStatisticsType, Long>> values = select(TRIPLE_MAPPER)
                .where(F.DOMAIN.eq(domain)).and(F.SOURCE.eq(source)).and(F.DATE.gte(from)).and(F.DATE.lte(to))
                .queryForList();

        TreeMap<LocalDate, EnumMap<TurboHostStatisticsType, Long>> result = new TreeMap<>();
        for (Triple<LocalDate, TurboHostStatisticsType, Long> triple : values) {
            result.computeIfAbsent(triple.getLeft(), k -> new EnumMap<>(TurboHostStatisticsType.class))
                    .compute(triple.getMiddle(), (k, v) -> (v == null ? 0 : v) + triple.getRight());
        }
        return result;
    }

    public TurboTotalStatistics getFeedStatistics(String domain, LocalDate date, String feed, TurboFeedType type)  {
        List<TurboDomainStatistics> statsList = select(MAPPER)
                .where(F.DOMAIN.eq(domain)).and(F.SOURCE.eq(type)).and(F.DATE.eq(date)).and(F.FEED.eq(feed))
                .queryForList();
        TurboTotalStatisticsBuilder builder = new TurboTotalStatisticsBuilder();
        statsList.forEach(builder::add);
        return builder.build();
    }

    private interface F {
        Field<String> DOMAIN = Fields.stringField("domain");
        Field<TurboFeedType> SOURCE = Fields.intEnumField("source", TurboFeedType.R);
        Field<LocalDate> DATE = Fields.jodaDateField("date");
        Field<String> FEED = Fields.stringField("feed");
        Field<TurboHostStatisticsType> TYPE = Fields.intEnumField("type", TurboHostStatisticsType.R);
        Field<Long> VALUE = Fields.longField("value");
    }
}
