using SatelliteProvider.Common.DTO;
using SatelliteProvider.Common.Utils;

namespace SatelliteProvider.Services.RouteManagement;

public class GeofenceGridCalculator
{
    public IReadOnlyList<GeoPoint> GenerateRegions(GeoPoint northWest, GeoPoint southEast, double regionSizeMeters)
    {
        ArgumentNullException.ThrowIfNull(northWest);
        ArgumentNullException.ThrowIfNull(southEast);
        if (regionSizeMeters <= 0)
        {
            throw new ArgumentOutOfRangeException(nameof(regionSizeMeters), "Region size must be positive");
        }

        var midLon = (northWest.Lon + southEast.Lon) / 2;
        var midLat = (northWest.Lat + southEast.Lat) / 2;

        var heightMeters = GeoUtils.CalculateDistance(
            new GeoPoint(northWest.Lat, midLon),
            new GeoPoint(southEast.Lat, midLon));
        var widthMeters = GeoUtils.CalculateDistance(
            new GeoPoint(midLat, northWest.Lon),
            new GeoPoint(midLat, southEast.Lon));

        var numLatSteps = Math.Max(1, (int)Math.Ceiling(heightMeters / regionSizeMeters));
        var numLonSteps = Math.Max(1, (int)Math.Ceiling(widthMeters / regionSizeMeters));

        var latStep = (northWest.Lat - southEast.Lat) / numLatSteps;
        var lonStep = (southEast.Lon - northWest.Lon) / numLonSteps;

        var regions = new List<GeoPoint>(numLatSteps * numLonSteps);
        for (int latIdx = 0; latIdx < numLatSteps; latIdx++)
        {
            for (int lonIdx = 0; lonIdx < numLonSteps; lonIdx++)
            {
                var lat = northWest.Lat - (latIdx + 0.5) * latStep;
                var lon = northWest.Lon + (lonIdx + 0.5) * lonStep;
                regions.Add(new GeoPoint(lat, lon));
            }
        }

        return regions;
    }
}
