package ru.yandex.webmaster3.viewer.http.links2;

import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Set;
import java.util.TreeMap;

import com.google.common.collect.Lists;
import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Required;

import ru.yandex.autodoc.common.doc.annotation.Description;
import ru.yandex.webmaster3.core.codes.LinkType;
import ru.yandex.webmaster3.core.metrics.Category;
import ru.yandex.webmaster3.core.http.ReadAction;
import ru.yandex.webmaster3.core.link.LinkHistoryIndicatorType;
import ru.yandex.webmaster3.storage.links.LinksService;
import ru.yandex.webmaster3.viewer.http.AbstractUserVerifiedHostAction;
import ru.yandex.webmaster3.viewer.http.links.HistoryUtil;

/**
 * @author tsyplyaev
 */
@ReadAction
@Description("Ручка для графиков истории по количеству внутренних ссылок и хостов")
@Category("links")
public class GetLinksHistoryAction extends AbstractUserVerifiedHostAction<GetLinksHistoryRequest, GetLinksHistoryResponse> {
    private LinksService linksService;

    @Override
    public GetLinksHistoryResponse process(GetLinksHistoryRequest request) {
        Map<LinkHistoryIndicatorType, NavigableMap<LocalDate, Long>> simpleHistory =
                linksService.getSimpleHistory(request.getHostId(), request.getDateFrom(), request.getDateTo());

        NavigableMap<LocalDate, Long> externalUrlsCount = simpleHistory.computeIfAbsent(
                LinkHistoryIndicatorType.EXTERNAL_LINK_URLS_COUNT,
                k -> new TreeMap<>()
        );
        NavigableMap<LocalDate, Long> externalHostsCount = simpleHistory.computeIfAbsent(
                LinkHistoryIndicatorType.EXTERNAL_LINK_HOSTS_COUNT,
                k -> new TreeMap<>()
        );
        NavigableMap<LocalDate, Long> externalNewUrlsCount = simpleHistory.computeIfAbsent(
                LinkHistoryIndicatorType.EXTERNAL_LINK_NEW_URLS_COUNT,
                k -> new TreeMap<>()
        );
        NavigableMap<LocalDate, Long> externalNewHostsCount = simpleHistory.computeIfAbsent(
                LinkHistoryIndicatorType.EXTERNAL_LINK_NEW_HOSTS_COUNT,
                k -> new TreeMap<>()
        );
        NavigableMap<LocalDate, Long> externalGoneUrlsCount = simpleHistory.computeIfAbsent(
                LinkHistoryIndicatorType.EXTERNAL_LINK_GONE_URLS_COUNT,
                k -> new TreeMap<>()
        );
        NavigableMap<LocalDate, Long> externalGoneHostsCount = simpleHistory.computeIfAbsent(
                LinkHistoryIndicatorType.EXTERNAL_LINK_GONE_HOSTS_COUNT,
                k -> new TreeMap<>()
        );

        NavigableMap<LocalDate, Long> externalBrokenUrlHistory = mergeHistories(
                linksService.getExternalHttpHistory(request.getHostId(), request.getDateFrom(), request.getDateTo(), p -> LinkType.isBroken(p)).values()
        );

        return new GetLinksHistoryResponse.OrdinaryResponse(Lists.newArrayList(
                new GetLinksHistoryResponse.LinkHistory(GetLinksHistoryResponse.Indicator.LINKS_EXTERNAL_URLS, HistoryUtil.toDataPoint(externalUrlsCount)),
                new GetLinksHistoryResponse.LinkHistory(GetLinksHistoryResponse.Indicator.LINKS_EXTERNAL_HOSTS, HistoryUtil.toDataPoint(externalHostsCount)),
                new GetLinksHistoryResponse.LinkHistory(GetLinksHistoryResponse.Indicator.LINKS_EXTERNAL_NEW_URLS, HistoryUtil.toDataPoint(externalNewUrlsCount)),
                new GetLinksHistoryResponse.LinkHistory(GetLinksHistoryResponse.Indicator.LINKS_EXTERNAL_NEW_HOSTS, HistoryUtil.toDataPoint(externalNewHostsCount)),
                new GetLinksHistoryResponse.LinkHistory(GetLinksHistoryResponse.Indicator.LINKS_EXTERNAL_GONE_URLS, HistoryUtil.toDataPoint(externalGoneUrlsCount)),
                new GetLinksHistoryResponse.LinkHistory(GetLinksHistoryResponse.Indicator.LINKS_EXTERNAL_GONE_HOSTS, HistoryUtil.toDataPoint(externalGoneHostsCount)),
                new GetLinksHistoryResponse.LinkHistory(GetLinksHistoryResponse.Indicator.LINKS_EXTERNAL_BROKEN_URLS, HistoryUtil.toDataPoint(externalBrokenUrlHistory))
        ));
    }

    static NavigableMap<LocalDate, Long> mergeHistories(Collection<NavigableMap<LocalDate, Long>> values) {
        Set<LocalDate> dates = new HashSet<>();
        values.forEach(e -> dates.addAll(e.keySet()));

        NavigableMap<LocalDate, Long> result = new TreeMap<>();
        dates.forEach(d -> result.put(d, 0L));

        values.forEach(e -> e.entrySet().forEach(
                ee -> result.put(ee.getKey(), result.get(ee.getKey()) + ee.getValue()))
        );
        return result;
    }

    @Required
    public void setLinksService(LinksService linksService) {
        this.linksService = linksService;
    }
}
