package ru.yandex.webmaster3.api.queries2.action.util;

import com.google.common.collect.Range;
import com.google.common.collect.RangeSet;
import org.apache.commons.lang3.tuple.Pair;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import ru.yandex.webmaster3.api.http.common.data.ApiHistoryPoint;
import ru.yandex.webmaster3.api.queries.data.ApiQueryIndicator;
import ru.yandex.webmaster3.storage.searchquery.AccumulatorMap;
import ru.yandex.webmaster3.storage.searchquery.DayStat;

import java.util.Collection;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author leonidrom
 */
public class QueriesUtil {
    /**
     * Преобразует список со статистикой в мапу с индикаторами в качестве ключа,
     * попутно аккумулируя значения в рамках указанных диапазонов дат.
     *
     * @param apiIndicators индикаторы, которые будут клюяами мапы
     * @param stats список со статистикой по дням
     * @param rangeSet диапазоны аккумуляции значений
     */
    public static <T extends DayStat> Map<ApiQueryIndicator, List<ApiHistoryPoint<Double>>> accumulateIndicatorsHistory(
            Collection<ApiQueryIndicator> apiIndicators, List<T> stats, RangeSet<LocalDate> rangeSet) {
        var coreIndicators = apiIndicators.stream()
                .map(ApiQueryIndicator::getCoreQueryIndicator)
                .collect(Collectors.toList());

        // инициализируем аккумулятор
        var accumulatorMap = AccumulatorMap.create(coreIndicators, rangeSet);
        stats.forEach(accumulatorMap::apply);

        Map<ApiQueryIndicator, List<ApiHistoryPoint<Double>>> indicatorsHistory = new EnumMap<>(ApiQueryIndicator.class);
        for (var apiIndicator : apiIndicators) {
            // аккумулируем статистику для индикатора
            List<Pair<Range<LocalDate>, Double>> accumulatedStats = accumulatorMap.getIndicator(apiIndicator.getCoreQueryIndicator());

            // соберем аккумулированную статистику в список нужного нам вида
            List<ApiHistoryPoint<Double>> indicatorHistoryPoints = accumulatedStats.stream()
                    .filter(pair -> pair.getRight() != null) // оставим только дни со значениями
                    .map(pair -> {
                        DateTime date = pair.getLeft().lowerEndpoint().toDateTimeAtStartOfDay();
                        Double value = pair.getRight();
                        return new ApiHistoryPoint<>(date, value);
                    })
                    .collect(Collectors.toList());

            // и положим его в мапу
            indicatorsHistory.put(apiIndicator, indicatorHistoryPoints);
        }

        return indicatorsHistory;
    }
}
