using FluentAssertions;
using SatelliteProvider.DataAccess.Models;
using SatelliteProvider.Services.RouteManagement;

namespace SatelliteProvider.Tests;

// AZ-364 / C11: pure-helper tests for the route-point ↔ region nearest-
// neighbour matcher extracted from RouteProcessingService.
public class RouteRegionMatcherTests
{
    [Fact]
    public void Match_OrdersRegionsToFollowRoutePointSequence_AZ364_AC1()
    {
        // Arrange
        var sut = new RouteRegionMatcher();

        var routePoints = new List<RoutePointEntity>
        {
            new() { Latitude = 0.0, Longitude = 0.0, SequenceNumber = 0 },
            new() { Latitude = 1.0, Longitude = 0.0, SequenceNumber = 1 },
            new() { Latitude = 2.0, Longitude = 0.0, SequenceNumber = 2 },
        };

        var regionFar = new RegionEntity { Id = Guid.NewGuid(), Latitude = 2.0, Longitude = 0.0 };
        var regionNear = new RegionEntity { Id = Guid.NewGuid(), Latitude = 0.0, Longitude = 0.0 };
        var regionMid = new RegionEntity { Id = Guid.NewGuid(), Latitude = 1.0, Longitude = 0.0 };

        var unorderedRegions = new List<RegionEntity> { regionFar, regionNear, regionMid };

        // Act
        var ordered = sut.Match(routePoints, unorderedRegions);

        // Assert
        ordered.Should().HaveCount(3);
        ordered[0].Id.Should().Be(regionNear.Id);
        ordered[1].Id.Should().Be(regionMid.Id);
        ordered[2].Id.Should().Be(regionFar.Id);
    }

    [Fact]
    public void Match_ConsumesEachRegionAtMostOnce_AZ364_AC1()
    {
        // Arrange
        var sut = new RouteRegionMatcher();
        var sharedRegion = new RegionEntity { Id = Guid.NewGuid(), Latitude = 0.0, Longitude = 0.0 };
        var otherRegion = new RegionEntity { Id = Guid.NewGuid(), Latitude = 10.0, Longitude = 0.0 };

        var routePoints = new List<RoutePointEntity>
        {
            new() { Latitude = 0.0, Longitude = 0.0, SequenceNumber = 0 },
            new() { Latitude = 0.001, Longitude = 0.0, SequenceNumber = 1 },
        };

        // Act
        var ordered = sut.Match(routePoints, new List<RegionEntity> { sharedRegion, otherRegion });

        // Assert
        ordered.Should().HaveCount(2);
        ordered.Select(r => r.Id).Should().OnlyHaveUniqueItems();
        ordered[0].Id.Should().Be(sharedRegion.Id);
        ordered[1].Id.Should().Be(otherRegion.Id);
    }

    [Fact]
    public void Match_FewerRegionsThanPoints_ReturnsAvailableSubset_AZ364_AC1()
    {
        // Arrange
        var sut = new RouteRegionMatcher();
        var soleRegion = new RegionEntity { Id = Guid.NewGuid(), Latitude = 0.0, Longitude = 0.0 };

        var routePoints = new List<RoutePointEntity>
        {
            new() { Latitude = 0.0, Longitude = 0.0, SequenceNumber = 0 },
            new() { Latitude = 1.0, Longitude = 0.0, SequenceNumber = 1 },
        };

        // Act
        var ordered = sut.Match(routePoints, new List<RegionEntity> { soleRegion });

        // Assert
        ordered.Should().HaveCount(1);
        ordered[0].Id.Should().Be(soleRegion.Id);
    }

    [Fact]
    public void Match_NullArguments_Throws_AZ364_AC1()
    {
        // Arrange
        var sut = new RouteRegionMatcher();

        // Act
        Action actNullPoints = () => sut.Match(null!, new List<RegionEntity>());
        Action actNullRegions = () => sut.Match(new List<RoutePointEntity>(), null!);

        // Assert
        actNullPoints.Should().Throw<ArgumentNullException>();
        actNullRegions.Should().Throw<ArgumentNullException>();
    }
}
