package ru.yandex.webmaster3.api.queries.action;

import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.tuple.Pair;
import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import ru.yandex.autodoc.common.doc.annotation.Description;
import ru.yandex.webmaster3.api.http.auth.ActionPermission;
import ru.yandex.webmaster3.api.http.auth.Permission;
import ru.yandex.webmaster3.api.http.rest.AbstractApiAction;
import ru.yandex.webmaster3.api.queries.data.ApiQueryIndicator;
import ru.yandex.webmaster3.api.queries.data.ApiQueryStats;
import ru.yandex.webmaster3.core.metrics.Category;
import ru.yandex.webmaster3.core.searchquery.OrderDirection;
import ru.yandex.webmaster3.core.searchquery.QueryId;
import ru.yandex.webmaster3.core.searchquery.QueryIndicator;
import ru.yandex.webmaster3.core.searchquery.SpecialGroup;
import ru.yandex.webmaster3.core.util.TimeUtils;
import ru.yandex.webmaster3.storage.searchquery.DeviceType;
import ru.yandex.webmaster3.storage.searchquery.QueryStat;
import ru.yandex.webmaster3.storage.searchquery.QueryStatisticsService2;
import ru.yandex.webmaster3.storage.searchquery.RegionInclusion;
import ru.yandex.webmaster3.storage.searchquery.SearchqueryDatesService;
import ru.yandex.webmaster3.storage.searchquery.util.Accumulator;
import ru.yandex.webmaster3.storage.searchquery.util.ExtractorFactory;

/**
 * @author avhaliullin
 */
@Description("Получить список топ-500 популярных поисковых запросов, по которым сайт показывался на поиске за последнюю неделю")
@Category("searchquery")
@Component
@ActionPermission(Permission.COMMON)
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class ListQueriesAction extends AbstractApiAction<ListQueriesRequest, ListQueriesResponse> {
    private static final int PERIOD_DAYS = 7;
    private static final int QUERIES_LIMIT = 500;

    private final QueryStatisticsService2 queryStatisticsService2;
    private final SearchqueryDatesService searchqueryDatesService;

    @Override
    public ListQueriesResponse process(ListQueriesRequest request) {
        Pair<LocalDate, LocalDate> dates = searchqueryDatesService.getDates();
        LocalDate maxDate = dates.getRight(); // https://youtrack.jetbrains.com/issue/IDEA-159896
        LocalDate desiredMinDate = maxDate.minusDays(PERIOD_DAYS - 1);
        LocalDate minDate = TimeUtils.latestOf(desiredMinDate, dates.getLeft());
        List<QueryId> queryIds = queryStatisticsService2.getQueryIds(
                request.getHostId(),
                SpecialGroup.TOP_3000_QUERIES,
                Collections.emptySet(),
                RegionInclusion.INCLUDE_ALL,
                minDate,
                maxDate,
                Collections.emptyList(),
                DeviceType.ALL_DEVICES,
                request.getOrderBy().getQueryIndicator(),
                OrderDirection.DESC,
                0,
                QUERIES_LIMIT
        );
        List<QueryIndicator> requestedIndicators = new ArrayList<>();
        for (ApiQueryIndicator apiQueryIndicator : request.getQueryIndicators()) {
            requestedIndicators.add(apiQueryIndicator.getCoreQueryIndicator());
        }
        Pair<Map<QueryId, String>, List<QueryStat>> queryTextsAndStats =
                queryStatisticsService2.getQueryStatistics(
                        request.getHostId(),
                        SpecialGroup.TOP_3000_QUERIES,
                        requestedIndicators,
                        RegionInclusion.INCLUDE_ALL,
                        Collections.emptySet(),
                        queryIds,
                        minDate,
                        maxDate,
                        DeviceType.ALL_DEVICES
                );
        Map<QueryId, List<QueryStat>> query2Stat = queryTextsAndStats.getRight().stream()
                .collect(Collectors.groupingBy(QueryStat::getQueryId));

        List<ApiQueryStats> result = new ArrayList<>();
        for (QueryId queryId : queryIds) {
            Map<ApiQueryIndicator, Accumulator> indicatorAccs = new EnumMap<>(ApiQueryIndicator.class);
            for (ApiQueryIndicator queryIndicator : request.getQueryIndicators()) {
                indicatorAccs.put(queryIndicator, ExtractorFactory.createExtractor(queryIndicator.getCoreQueryIndicator()));
            }
            if (query2Stat.containsKey(queryId)) {
                for (QueryStat stat : query2Stat.get(queryId)) {
                    for (Accumulator acc : indicatorAccs.values()) {
                        acc.apply(stat);
                    }
                }
            }
            Map<ApiQueryIndicator, Double> indicatorValues = new EnumMap<>(ApiQueryIndicator.class);
            for (Map.Entry<ApiQueryIndicator, Accumulator> accEntry : indicatorAccs.entrySet()) {
                Double value = accEntry.getValue().getValue();
                indicatorValues.put(accEntry.getKey(), value);
            }
            result.add(new ApiQueryStats(
                    queryId,
                    queryTextsAndStats.getLeft().get(queryId),
                    indicatorValues
            ));
        }
        return new ListQueriesResponse(result, minDate, maxDate);
    }
}
