using Kompas.Mcp.Core.Documents;
using Kompas.Mcp.Core.Drawings;
using Kompas.Mcp.Core.Modeling;

namespace Kompas.Mcp.Tests.Integration;

/// <summary>Интеграция: угловой размер на виде (API7 ISymbols2DContainer.AngleDimensions).</summary>
[Trait("Category", "Integration")]
[Collection(KompasCollection.Name)]
public sealed class DrawingAngularTests : IntegrationTestBase
{
    private readonly DocumentService _docs;
    private readonly PartModeler _modeler;
    private readonly DrawingService _drawing;

    public DrawingAngularTests(KompasFixture fx) : base(fx)
    {
        _docs = new DocumentService(fx.Session, fx.Dispatcher);
        _modeler = new PartModeler(fx.Session, fx.Dispatcher);
        _drawing = new DrawingService(fx.Session, fx.Dispatcher);
    }

    private async Task<string> BuildAndSaveBoxAsync()
    {
        var path = TestPaths.NewFile(".m3d");
        await _docs.CreateAsync(KompasDocumentType.Part);
        try
        {
            var s = await _modeler.OpenSketchAsync(BasePlane.XOY);
            await _modeler.AddRectangleAsync(s, 0, 0, 40, 30);
            await _modeler.CloseSketchAsync(s);
            await _modeler.ExtrudeAsync(s, depth: 20);
            await _modeler.RebuildAsync();
            await _docs.SaveAsAsync(path);
        }
        finally { await _docs.CloseAsync(save: false); }
        return path;
    }

    private async Task<string> NewDrawingWithViewsAsync()
    {
        var partFile = await BuildAndSaveBoxAsync();
        await _docs.CreateAsync(KompasDocumentType.Drawing);
        await _drawing.CreateStandardViewsAsync(partFile, 1.0, 100, 150);
        return partFile;
    }

    [Fact]
    public async Task Angular_measures_right_angle()
    {
        await NewDrawingWithViewsAsync();
        try
        {
            // Вершина (0,0); сторона1 → (10,0); сторона2 → (0,10); дуга в секторе (5,5) → 90°.
            var r = await _drawing.AddAngularDimensionAsync(
                viewNumber: 0, xc: 0, yc: 0, x1: 10, y1: 0, x2: 0, y2: 10, x3: 5, y3: 5,
                angleType: AngleDimensionType.Min);
            Assert.InRange(r.Value, 89.5, 90.5);
        }
        finally { await _docs.CloseAsync(save: false); }
    }

    [Fact]
    public async Task Angular_measures_45_degrees()
    {
        await NewDrawingWithViewsAsync();
        try
        {
            // Вершина (0,0); сторона1 → (10,0); сторона2 → (10,10) (45°); дуга (8,4).
            var r = await _drawing.AddAngularDimensionAsync(
                viewNumber: 0, xc: 0, yc: 0, x1: 10, y1: 0, x2: 10, y2: 10, x3: 8, y3: 4,
                angleType: AngleDimensionType.Min);
            Assert.InRange(r.Value, 44.5, 45.5);
        }
        finally { await _docs.CloseAsync(save: false); }
    }

    [Fact]
    public async Task Angle_type_max_measures_larger_angle()
    {
        await NewDrawingWithViewsAsync();
        try
        {
            // Лучи 0° и 45°: три типа дают разные углы — min=45 (острый), max=135 (тупой
            // супплемент 180−45), more=315 (рефлексный). Покрывает маппинг ksADMaxAngle (≠ Min/More).
            var r = await _drawing.AddAngularDimensionAsync(
                viewNumber: 0, xc: 0, yc: 0, x1: 10, y1: 0, x2: 10, y2: 10, x3: 4, y3: -8,
                angleType: AngleDimensionType.Max);
            Assert.InRange(r.Value, 134.0, 136.0);
        }
        finally { await _docs.CloseAsync(save: false); }
    }

    [Fact]
    public async Task Targets_specific_view_and_increments_angular_count()
    {
        var partFile = await BuildAndSaveBoxAsync();
        await _docs.CreateAsync(KompasDocumentType.Drawing);
        try
        {
            var views = await _drawing.CreateStandardViewsAsync(partFile, 1.0, 100, 150);
            var targetNumber = views.ViewNumbers[1];

            var before = await _drawing.GetViewAngularDimensionCountAsync(targetNumber);
            var r = await _drawing.AddAngularDimensionAsync(
                targetNumber, xc: 0, yc: 0, x1: 10, y1: 0, x2: 0, y2: 10, x3: 5, y3: 5,
                angleType: AngleDimensionType.Min);
            var after = await _drawing.GetViewAngularDimensionCountAsync(targetNumber);

            Assert.Equal(targetNumber, r.ViewNumber);
            Assert.Equal(before + 1, after);
            Assert.InRange(r.Value, 89.5, 90.5);
        }
        finally { await _docs.CloseAsync(save: false); }
    }

    [Fact]
    public async Task Angle_type_more_measures_reflex_angle()
    {
        await NewDrawingWithViewsAsync();
        try
        {
            // Та же геометрия 90°, но angleType=more → измеряется рефлексный угол ~270°.
            // Тип угла (min/max/more) выбирает, какой из секторов измерять; (x3,y3) лишь
            // позиционирует размерную дугу (её ставим в рефлексный сектор для согласованности).
            var r = await _drawing.AddAngularDimensionAsync(
                viewNumber: 0, xc: 0, yc: 0, x1: 10, y1: 0, x2: 0, y2: 10, x3: -5, y3: -5,
                angleType: AngleDimensionType.More);
            Assert.InRange(r.Value, 269.0, 271.0);
        }
        finally { await _docs.CloseAsync(save: false); }
    }

    [Fact]
    public async Task Coincident_vertex_and_side_throws()
    {
        await NewDrawingWithViewsAsync();
        try
        {
            // Вершина совпадает с точкой стороны1 → вырождение до Add.
            await Assert.ThrowsAsync<ArgumentException>(() =>
                _drawing.AddAngularDimensionAsync(
                    viewNumber: 0, xc: 0, yc: 0, x1: 0, y1: 0, x2: 0, y2: 10, x3: 5, y3: 5,
                    angleType: AngleDimensionType.Min));
        }
        finally { await _docs.CloseAsync(save: false); }
    }

    [Fact]
    public async Task Collinear_rays_rollback_leaves_count_unchanged()
    {
        await NewDrawingWithViewsAsync();
        try
        {
            var before = await _drawing.GetViewAngularDimensionCountAsync(0);
            // Сонаправленные лучи (0,0)→(10,0) и (0,0)→(20,0): угол ≈0 → пост-проверка → откат.
            await Assert.ThrowsAsync<InvalidOperationException>(() =>
                _drawing.AddAngularDimensionAsync(
                    viewNumber: 0, xc: 0, yc: 0, x1: 10, y1: 0, x2: 20, y2: 0, x3: 15, y3: 5,
                    angleType: AngleDimensionType.Min));
            var after = await _drawing.GetViewAngularDimensionCountAsync(0);
            Assert.Equal(before, after);
        }
        finally { await _docs.CloseAsync(save: false); }
    }

    [Fact]
    public async Task No_views_throws()
    {
        await _docs.CreateAsync(KompasDocumentType.Drawing);
        try
        {
            await Assert.ThrowsAsync<InvalidOperationException>(() =>
                _drawing.AddAngularDimensionAsync(
                    viewNumber: 0, xc: 0, yc: 0, x1: 10, y1: 0, x2: 0, y2: 10, x3: 5, y3: 5,
                    angleType: AngleDimensionType.Min));
        }
        finally { await _docs.CloseAsync(save: false); }
    }

    [Fact]
    public async Task Unknown_view_number_throws()
    {
        await NewDrawingWithViewsAsync();
        try
        {
            await Assert.ThrowsAsync<InvalidOperationException>(() =>
                _drawing.AddAngularDimensionAsync(
                    viewNumber: 999, xc: 0, yc: 0, x1: 10, y1: 0, x2: 0, y2: 10, x3: 5, y3: 5,
                    angleType: AngleDimensionType.Min));
        }
        finally { await _docs.CloseAsync(save: false); }
    }
}
