using Theriapolis.Core;
using Theriapolis.Core.Entities;
using Theriapolis.Core.World;
using Xunit;

namespace Theriapolis.Tests.Entities;

public sealed class WorldTravelPlannerTests : IClassFixture<WorldCache>
{
    private const ulong TestSeed = 0xCAFEBABEUL;
    private readonly WorldCache _cache;
    public WorldTravelPlannerTests(WorldCache c) => _cache = c;

    [Fact]
    public void Plan_BetweenAdjacentSettlements_ReturnsConnectedPath()
    {
        var w = _cache.Get(TestSeed).World;
        var inhabited = w.Settlements.Where(s => !s.IsPoi && s.Tier <= 3).Take(2).ToArray();
        Assert.Equal(2, inhabited.Length);

        var planner = new WorldTravelPlanner(w);
        var path = planner.PlanTilePath(inhabited[0].TileX, inhabited[0].TileY,
                                         inhabited[1].TileX, inhabited[1].TileY);
        Assert.NotNull(path);
        Assert.True(path!.Count >= 2);
        // Endpoints match the request.
        Assert.Equal((inhabited[0].TileX, inhabited[0].TileY), path[0]);
        Assert.Equal((inhabited[1].TileX, inhabited[1].TileY), path[^1]);
        // No teleporting — every adjacent pair is within Chebyshev 1.
        for (int i = 1; i < path.Count; i++)
        {
            int dx = Math.Abs(path[i].X - path[i - 1].X);
            int dy = Math.Abs(path[i].Y - path[i - 1].Y);
            Assert.True(dx <= 1 && dy <= 1);
            Assert.False(dx == 0 && dy == 0);
        }
    }

    [Fact]
    public void Plan_FromOcean_ReturnsNull()
    {
        var w = _cache.Get(TestSeed).World;
        // Find an ocean tile and a land tile.
        (int ox, int oy) = (-1, -1);
        for (int y = 0; y < C.WORLD_HEIGHT_TILES && oy < 0; y++)
        for (int x = 0; x < C.WORLD_WIDTH_TILES  && oy < 0; x++)
            if (w.TileAt(x, y).Biome == BiomeId.Ocean) { ox = x; oy = y; }
        Assert.True(ox >= 0, "world should have at least one ocean tile");

        var inhabited = w.Settlements.First(s => !s.IsPoi);
        var planner = new WorldTravelPlanner(w);
        var path = planner.PlanTilePath(ox, oy, inhabited.TileX, inhabited.TileY);
        Assert.Null(path);
    }
}
