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

namespace Kompas.Mcp.Tests.Integration;

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

    public DrawingDimensionTests(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;
    }

    [Fact]
    public async Task Horizontal_dimension_auto_measures_distance()
    {
        var partFile = await BuildAndSaveBoxAsync();
        await _docs.CreateAsync(KompasDocumentType.Drawing);
        try
        {
            var views = await _drawing.CreateStandardViewsAsync(partFile, 1.0, 100, 150);
            Assert.Equal(3, views.ViewNumbers.Count);

            var r = await _drawing.AddLinearDimensionAsync(
                viewNumber: 0, x1: 0, y1: 0, x2: 40, y2: 0, x3: 20, y3: -10, DimensionOrientation.Horizontal);

            Assert.InRange(r.Value, 39.9, 40.1);          // авто-значение = |X2-X1|
            Assert.Contains(r.ViewNumber, views.ViewNumbers); // размер попал в один из видов
        }
        finally { await _docs.CloseAsync(save: false); }
    }

    [Fact]
    public async Task Vertical_dimension_measures_y_span()
    {
        var partFile = await BuildAndSaveBoxAsync();
        await _docs.CreateAsync(KompasDocumentType.Drawing);
        try
        {
            await _drawing.CreateStandardViewsAsync(partFile, 1.0, 100, 150);
            var r = await _drawing.AddLinearDimensionAsync(
                viewNumber: 0, x1: 0, y1: 0, x2: 0, y2: 20, x3: -10, y3: 10, DimensionOrientation.Vertical);
            Assert.InRange(r.Value, 19.9, 20.1);
        }
        finally { await _docs.CloseAsync(save: false); }
    }

    [Fact]
    public async Task Targets_specific_view_by_number_and_increments_its_object_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]; // второй созданный вид (напр. сверху)

            // Размеры живут в ISymbols2DContainer вида — считаем именно их у ЦЕЛЕВОГО вида.
            var before = await _drawing.GetViewLineDimensionCountAsync(targetNumber);
            var r = await _drawing.AddLinearDimensionAsync(
                viewNumber: targetNumber, x1: 0, y1: 0, x2: 40, y2: 0, x3: 20, y3: -10, DimensionOrientation.Horizontal);
            var after = await _drawing.GetViewLineDimensionCountAsync(targetNumber);

            Assert.Equal(targetNumber, r.ViewNumber);
            Assert.Equal(before + 1, after); // размер попал именно в целевой вид
        }
        finally { await _docs.CloseAsync(save: false); }
    }

    [Fact]
    public async Task Parallel_dimension_measures_true_length()
    {
        var partFile = await BuildAndSaveBoxAsync();
        await _docs.CreateAsync(KompasDocumentType.Drawing);
        try
        {
            await _drawing.CreateStandardViewsAsync(partFile, 1.0, 100, 150);
            // Параллельный размер (0,0)-(30,40): реальная длина = 50 (3-4-5).
            var r = await _drawing.AddLinearDimensionAsync(
                viewNumber: 0, x1: 0, y1: 0, x2: 30, y2: 40, x3: 25, y3: 5, DimensionOrientation.Parallel);
            Assert.InRange(r.Value, 49.5, 50.5);
        }
        finally { await _docs.CloseAsync(save: false); }
    }

    [Fact]
    public async Task Zero_projection_orientation_throws_and_rolls_back()
    {
        var partFile = await BuildAndSaveBoxAsync();
        await _docs.CreateAsync(KompasDocumentType.Drawing);
        try
        {
            await _drawing.CreateStandardViewsAsync(partFile, 1.0, 100, 150);
            var before = await _drawing.GetViewLineDimensionCountAsync(0);

            // Горизонтальный размер для точек на одной вертикали → |X2-X1|=0 → ошибка + откат.
            await Assert.ThrowsAsync<InvalidOperationException>(() => _drawing.AddLinearDimensionAsync(
                viewNumber: 0, x1: 10, y1: 0, x2: 10, y2: 30, x3: 0, y3: 15, DimensionOrientation.Horizontal));

            // Откат: число размеров не изменилось (вырожденный размер удалён).
            var after = await _drawing.GetViewLineDimensionCountAsync(0);
            Assert.Equal(before, after);
        }
        finally { await _docs.CloseAsync(save: false); }
    }

    [Fact]
    public async Task Coincident_points_throw()
    {
        var partFile = await BuildAndSaveBoxAsync();
        await _docs.CreateAsync(KompasDocumentType.Drawing);
        try
        {
            await _drawing.CreateStandardViewsAsync(partFile, 1.0, 100, 150);
            await Assert.ThrowsAsync<ArgumentException>(() => _drawing.AddLinearDimensionAsync(
                viewNumber: 0, x1: 10, y1: 10, x2: 10, y2: 10, x3: 0, y3: 0, DimensionOrientation.Horizontal));
        }
        finally { await _docs.CloseAsync(save: false); }
    }

    [Fact]
    public async Task No_views_throws()
    {
        // Чертёж без ассоциативных видов: только системный вид → понятная ошибка.
        await _docs.CreateAsync(KompasDocumentType.Drawing);
        try
        {
            await Assert.ThrowsAsync<InvalidOperationException>(() => _drawing.AddLinearDimensionAsync(
                viewNumber: 0, x1: 0, y1: 0, x2: 40, y2: 0, x3: 20, y3: -10, DimensionOrientation.Horizontal));
        }
        finally { await _docs.CloseAsync(save: false); }
    }
}
