using Kompas.Mcp.Core.Drawings;

namespace Kompas.Mcp.Tests;

[Trait("Category", "Unit")]
public sealed class CircularObjectMatchTests
{
    private const double Tol = 1.0;

    private static IReadOnlyList<CircleCandidate> Candidates(params (double x, double y, double r)[] items)
        => items.Select(i => new CircleCandidate(i.x, i.y, i.r)).ToList();

    [Fact]
    public void SelectMatchIndex_returns_unique_match()
    {
        var c = Candidates((0, 0, 10), (50, 20, 5));
        // ключ с допустимым отклонением центра и радиуса
        Assert.Equal(0, CircularObjectMatch.SelectMatchIndex(c, 0.3, -0.2, 10.3, Tol));
        Assert.Equal(1, CircularObjectMatch.SelectMatchIndex(c, 50, 20, 5, Tol));
    }

    [Fact]
    public void SelectMatchIndex_concentric_disambiguated_by_radius()
    {
        // концентрические R5 и R10 (цековка): ключ R10 выбирает внешнюю, не неоднозначно
        var c = Candidates((0, 0, 5), (0, 0, 10));
        Assert.Equal(1, CircularObjectMatch.SelectMatchIndex(c, 0, 0, 10, Tol));
        Assert.Equal(0, CircularObjectMatch.SelectMatchIndex(c, 0, 0, 5, Tol));
    }

    [Fact]
    public void SelectMatchIndex_throws_when_none_in_tolerance()
    {
        var c = Candidates((0, 0, 10));
        // центр далеко
        Assert.Throws<InvalidOperationException>(() => CircularObjectMatch.SelectMatchIndex(c, 100, 100, 10, Tol));
        // радиус далеко
        Assert.Throws<InvalidOperationException>(() => CircularObjectMatch.SelectMatchIndex(c, 0, 0, 25, Tol));
    }

    [Fact]
    public void SelectMatchIndex_throws_when_ambiguous()
    {
        // две почти совпадающие окружности в допуске
        var c = Candidates((0, 0, 10), (0.2, 0.2, 10.2));
        Assert.Throws<InvalidOperationException>(() => CircularObjectMatch.SelectMatchIndex(c, 0, 0, 10, Tol));
    }

    [Fact]
    public void SelectMatchIndex_throws_on_empty()
        => Assert.Throws<InvalidOperationException>(
            () => CircularObjectMatch.SelectMatchIndex(Candidates(), 0, 0, 10, Tol));
}
