using Kompas.Mcp.Core.Modeling;

namespace Kompas.Mcp.Tests;

[Trait("Category", "Unit")]
public sealed class SketchGeometryTests
{
    [Theory]
    [InlineData(true, 1)]
    [InlineData(false, -1)]
    public void ArcDirection_maps_orientation(bool ccw, int expected)
        => Assert.Equal(expected, (int)SketchGeometry.ArcDirection(ccw));

    [Theory]
    [InlineData(true, false)]   // вписанный → describe=false
    [InlineData(false, true)]   // описанный → describe=true
    public void PolygonDescribe_inverts_inscribed(bool inscribed, bool expected)
        => Assert.Equal(expected, SketchGeometry.PolygonDescribe(inscribed));

    [Theory]
    [InlineData("left", 0)]
    [InlineData("right", 1)]
    [InlineData("up", 2)]
    [InlineData("down", 3)]
    [InlineData("UP", 2)]
    public void RibSide_maps_known(string side, int expected)
        => Assert.Equal(expected, (int)SketchGeometry.RibSide(side));

    [Fact]
    public void RibSide_throws_on_unknown()
        => Assert.Throws<ArgumentException>(() => SketchGeometry.RibSide("diagonal"));

    [Fact]
    public void RequirePositive_throws_on_zero_or_negative()
    {
        Assert.Throws<ArgumentOutOfRangeException>(() => SketchGeometry.RequirePositive(0, "radius"));
        Assert.Throws<ArgumentOutOfRangeException>(() => SketchGeometry.RequirePositive(-1, "radius"));
        Assert.Null(Record.Exception(() => SketchGeometry.RequirePositive(0.1, "radius")));
    }

    [Fact]
    public void RequireVertexCount_throws_below_three()
    {
        Assert.Throws<ArgumentOutOfRangeException>(() => SketchGeometry.RequireVertexCount(2));
        Assert.Null(Record.Exception(() => SketchGeometry.RequireVertexCount(3)));
    }

    [Fact]
    public void RequireMin_throws_below_min()
    {
        Assert.Throws<ArgumentOutOfRangeException>(() => SketchGeometry.RequireMin(1, 2, "count"));
        Assert.Null(Record.Exception(() => SketchGeometry.RequireMin(2, 2, "count")));
        Assert.Null(Record.Exception(() => SketchGeometry.RequireMin(5, 2, "count")));
    }

    [Theory]
    [InlineData(0)]
    [InlineData(90)]
    [InlineData(-5)]
    [InlineData(120)]
    [InlineData(double.NaN)]
    [InlineData(double.PositiveInfinity)]
    public void RequireDraftAngle_rejects_out_of_range(double angle)
        => Assert.Throws<ArgumentOutOfRangeException>(() => SketchGeometry.RequireDraftAngle(angle, "angle"));

    [Theory]
    [InlineData(0.1)]
    [InlineData(45)]
    [InlineData(89.9)]
    public void RequireDraftAngle_passes_in_range(double angle)
        => Assert.Null(Record.Exception(() => SketchGeometry.RequireDraftAngle(angle, "angle")));

    [Fact]
    public void RequirePoints_throws_on_null()
        => Assert.Throws<ArgumentNullException>(
            () => SketchGeometry.RequirePoints(null!, 2, "points"));

    [Fact]
    public void RequirePoints_throws_when_too_few()
        => Assert.Throws<ArgumentException>(
            () => SketchGeometry.RequirePoints(new[] { (0.0, 0.0) }, 2, "points"));

    [Fact]
    public void RequirePoints_throws_on_non_finite()
        => Assert.Throws<ArgumentException>(
            () => SketchGeometry.RequirePoints(new[] { (0.0, 0.0), (double.NaN, 1.0) }, 2, "points"));

    [Fact]
    public void RequirePoints_passes_on_valid()
        => Assert.Null(Record.Exception(
            () => SketchGeometry.RequirePoints(new[] { (0.0, 0.0), (1.0, 1.0) }, 2, "points")));
}
