using FluentAssertions;
using SatelliteProvider.Common.DTO;
using SatelliteProvider.Common.Enums;
using SatelliteProvider.DataAccess.Models;
using SatelliteProvider.Services.RouteManagement;

namespace SatelliteProvider.Tests;

public class RouteResponseMapperTests
{
    private static RouteEntity BuildEntity(Guid id) => new()
    {
        Id = id,
        Name = "demo route",
        Description = "desc",
        RegionSizeMeters = 500,
        ZoomLevel = 18,
        TotalDistanceMeters = 1234.56,
        TotalPoints = 4,
        RequestMaps = true,
        MapsReady = false,
        CsvFilePath = "/ready/route.csv",
        SummaryFilePath = "/ready/route.txt",
        StitchedImagePath = "/ready/route.jpg",
        TilesZipPath = "/ready/route.zip",
        CreatedAt = new DateTime(2026, 1, 1, 0, 0, 0, DateTimeKind.Utc),
        UpdatedAt = new DateTime(2026, 1, 1, 0, 5, 0, DateTimeKind.Utc),
    };

    [Fact]
    public void Map_FromDtoPoints_CopiesAllEntityFields()
    {
        var id = Guid.NewGuid();
        var entity = BuildEntity(id);
        var dtos = new List<RoutePointDto>
        {
            new() { Latitude = 1, Longitude = 2, PointType = RoutePointType.Start, SequenceNumber = 0, SegmentIndex = 0 },
            new() { Latitude = 3, Longitude = 4, PointType = RoutePointType.End, SequenceNumber = 1, SegmentIndex = 1, DistanceFromPrevious = 100.0 },
        };
        var sut = new RouteResponseMapper();

        var response = sut.Map(entity, dtos);

        response.Id.Should().Be(id);
        response.Name.Should().Be(entity.Name);
        response.Description.Should().Be(entity.Description);
        response.RegionSizeMeters.Should().Be(entity.RegionSizeMeters);
        response.ZoomLevel.Should().Be(entity.ZoomLevel);
        response.TotalDistanceMeters.Should().Be(entity.TotalDistanceMeters);
        response.TotalPoints.Should().Be(entity.TotalPoints);
        response.RequestMaps.Should().Be(entity.RequestMaps);
        response.MapsReady.Should().Be(entity.MapsReady);
        response.CsvFilePath.Should().Be(entity.CsvFilePath);
        response.SummaryFilePath.Should().Be(entity.SummaryFilePath);
        response.StitchedImagePath.Should().Be(entity.StitchedImagePath);
        response.TilesZipPath.Should().Be(entity.TilesZipPath);
        response.CreatedAt.Should().Be(entity.CreatedAt);
        response.UpdatedAt.Should().Be(entity.UpdatedAt);
        response.Points.Should().BeEquivalentTo(dtos);
    }

    [Fact]
    public void Map_FromEntityPoints_ProjectsToDtosWithSameFields()
    {
        var id = Guid.NewGuid();
        var entity = BuildEntity(id);
        var pointEntities = new List<RoutePointEntity>
        {
            new() { Id = Guid.NewGuid(), RouteId = id, SequenceNumber = 0, Latitude = 1, Longitude = 2, PointType = RoutePointType.Start, SegmentIndex = 0 },
            new() { Id = Guid.NewGuid(), RouteId = id, SequenceNumber = 1, Latitude = 3, Longitude = 4, PointType = RoutePointType.End, SegmentIndex = 1, DistanceFromPrevious = 100.0 },
        };
        var sut = new RouteResponseMapper();

        var response = sut.Map(entity, pointEntities);

        response.Points.Should().HaveCount(2);
        response.Points[0].PointType.Should().Be(RoutePointType.Start);
        response.Points[0].Latitude.Should().Be(1);
        response.Points[1].PointType.Should().Be(RoutePointType.End);
        response.Points[1].DistanceFromPrevious.Should().Be(100.0);
    }

    [Fact]
    public void Map_NullEntity_Throws()
    {
        var sut = new RouteResponseMapper();

        Action act = () => sut.Map(null!, new List<RoutePointDto>());

        act.Should().Throw<ArgumentNullException>();
    }

    [Fact]
    public void Map_NullPoints_Throws()
    {
        var sut = new RouteResponseMapper();
        var entity = BuildEntity(Guid.NewGuid());

        Action act = () => sut.Map(entity, (IEnumerable<RoutePointDto>)null!);

        act.Should().Throw<ArgumentNullException>();
    }
}
