package com.livingworld.regions.query;

import java.util.Comparator;
import java.util.List;
import java.util.Optional;

import com.livingworld.regions.Region;
import com.livingworld.regions.RegionCoordinate;
import com.livingworld.regions.RegionMetrics;
import com.livingworld.regions.cache.RegionCache;

/**
 * Runs ecosystem-focused queries against active region data.
 */
public final class RegionQueryEngine {

    private static final Comparator<Region> BY_COORDINATE =
            Comparator.comparing((Region region) -> region.getCoordinate().dimensionId())
                    .thenComparingInt(region -> region.getCoordinate().x())
                    .thenComparingInt(region -> region.getCoordinate().z());

    private final RegionCache cache;

    public RegionQueryEngine(RegionCache cache) {
        if (cache == null) {
            throw new IllegalArgumentException("cache must not be null");
        }
        this.cache = cache;
    }

    public Optional<Region> getRegion(RegionCoordinate coordinate) {
        if (coordinate == null) {
            throw new IllegalArgumentException("coordinate must not be null");
        }
        return cache.get(coordinate);
    }

    public List<Region> getRegionsInRadius(RegionCoordinate center, int radius) {
        if (center == null) {
            throw new IllegalArgumentException("center must not be null");
        }
        if (radius < 0) {
            throw new IllegalArgumentException("radius must be non-negative");
        }

        return cache.allActive().stream()
                .filter(region -> region.getCoordinate().dimensionId().equals(center.dimensionId()))
                .filter(region -> Math.abs((long) region.getCoordinate().x() - center.x()) <= radius)
                .filter(region -> Math.abs((long) region.getCoordinate().z() - center.z()) <= radius)
                .sorted(BY_COORDINATE)
                .toList();
    }

    public List<Region> getRegionsWithActiveEcosystemEvent() {
        return cache.allActive().stream()
                .filter(region -> region.getFlags().isHasActiveEcosystemEvent())
                .sorted(BY_COORDINATE)
                .toList();
    }

    public List<Region> getRegionsAbovePollution(double threshold) {
        validateMetricThreshold(threshold);
        return cache.allActive().stream()
                .filter(region -> region.getMetrics().getPollutionScore() > threshold)
                .sorted(BY_COORDINATE)
                .toList();
    }

    public List<Region> getRegionsBelowSoilQuality(double threshold) {
        validateMetricThreshold(threshold);
        return cache.allActive().stream()
                .filter(region -> region.getMetrics().getSoilQuality() < threshold)
                .sorted(BY_COORDINATE)
                .toList();
    }

    private static void validateMetricThreshold(double threshold) {
        if (!Double.isFinite(threshold)
                || threshold < RegionMetrics.MIN_VALUE
                || threshold > RegionMetrics.MAX_VALUE) {
            throw new IllegalArgumentException("threshold must be finite and in range [0, 100]");
        }
    }
}
