package ru.yandex.webmaster3.storage.iks;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.tuple.Pair;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import ru.yandex.webmaster3.core.util.W3Collectors;
import ru.yandex.webmaster3.storage.iks.dao.IksUpdateDateYDao;

/**
 * Created by ifilippov5 on 28.08.18.
 */
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class IksHistoryService {
    private static final int CACHE_EXPIRATION_DURATION = 5; // minutes
    private static final Object CACHE_KEY = new Object();

    private final IksUpdateDateYDao iksUpdateDateYDao;

    private LoadingCache<Object, List<LocalDate>> iksUpdateDatesCache = CacheBuilder.newBuilder()
            .expireAfterWrite(CACHE_EXPIRATION_DURATION, TimeUnit.MINUTES)
            .build(CacheLoader.from(this::loadCache));

    private List<LocalDate> loadCache(Object key) {
        return iksUpdateDateYDao.iksUpdateDates().stream()
            .map(DateTime::toLocalDate)
            .distinct()
            .sorted(Collections.reverseOrder())
            .collect(Collectors.toList());
    }

    @VisibleForTesting
    static List<Pair<LocalDate, Long>> generateHistoryForEachDay(List<Pair<LocalDate, Long>> history, LocalDate dateFrom, LocalDate dateTo,
            List<LocalDate> iksUpdateTimes) {

        Map<LocalDate, Long> date2Iks = history.stream().collect(W3Collectors.toHashMap(W3Collectors.acceptAnyMerger()));
        for (LocalDate t : iksUpdateTimes) {
            date2Iks.putIfAbsent(t, 0L);
        }

        Long iks = null;
        List<Pair<LocalDate, Long>> answer = new ArrayList<>();
        for (LocalDate date = dateFrom; !date.isAfter(dateTo); date = date.plusDays(1)) {
            iks = date2Iks.getOrDefault(date, iks);
            if (iks != null) {
                answer.add(Pair.of(date, iks));
            }
        }
        return answer;
    }

    public List<Pair<LocalDate, Long>> mapDataToAllDays(List<Pair<LocalDate, Long>> data, LocalDate dateTo) {
        if (data == null || data.isEmpty()) {
            return new ArrayList<>();
        }
        return generateHistoryForEachDay(data, data.get(0).getKey(), dateTo, iksUpdateDatesCache.getUnchecked(CACHE_KEY));
    }

}
