package ru.yandex.webmaster3.monitoring.common;

import org.apache.commons.collections4.ComparatorUtils;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;
import ru.yandex.webmaster3.core.data.W3RegionInfo;
import ru.yandex.webmaster3.core.regions.RegionUtils;
import ru.yandex.webmaster3.core.regions.W3GeobaseService;
import ru.yandex.webmaster3.core.regions.W3RegionsTreeService;

import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author leonidrom
 */

/**
 * По техническим причинам мы не хотим зависеть от сервисов, поэтому используем здесь копию
 */
public class MonRegionsTreeService {
    private static final Logger log = LoggerFactory.getLogger(W3RegionsTreeService.class);

    private MonGeobaseService monGeobaseService;
    private final Map<Integer, Integer> regionId2VisibleParentId = new HashMap<>();
    private final Map<Integer, Set<Integer>> regionId2VisibleChildrenId = new HashMap<>();
    private final Map<Integer, W3RegionInfo> regionId2RegionInfo = new HashMap<>();

    public void init() {
        long startedAt = System.currentTimeMillis();
        log.info("W3RegionsTreeService initialization started");
        monGeobaseService.loadRegionsInfo(regionInfo -> {
            regionId2RegionInfo.put(regionInfo.getId(), regionInfo);
            if (regionInfo.getParentId() != null && !regionInfo.getParentId().equals(regionInfo.getId())) {
                regionId2VisibleParentId.put(regionInfo.getId(), regionInfo.getParentId());
                regionId2VisibleChildrenId.computeIfAbsent(regionInfo.getParentId(), x -> new TreeSet<>(ComparatorUtils.naturalComparator())).add(regionInfo.getId());
            }
        });

        log.info("W3RegionsService initialization finished in {} ms", System.currentTimeMillis() - startedAt);
    }


    @Nullable
    /**
     * Возвращает регион или его ближайшего родителя, удовлетворяющего предикату
     */
    public W3RegionInfo getVisibleRegionOrParent(int regionId, Predicate<W3RegionInfo> predicate) {
        W3RegionInfo regionInfo = regionId2RegionInfo.get(regionId);
        if (regionInfo == null) {
            return null;
        }
        if (!predicate.test(regionInfo)) {
            Integer parentId = regionInfo.getParentId();
            if (parentId == null) {
                return null;
            } else {
                return getVisibleRegionOrParent(parentId, predicate);
            }
        } else {
            return regionInfo;
        }
    }

    @Required
    public void setMonGeobaseService(MonGeobaseService monGeobaseService) {
        this.monGeobaseService = monGeobaseService;
    }
}
