using TraceCad.Core.Geometry;
using TraceCad.Core.Model;
using Xunit;

namespace TraceCad.Tests;

public sealed class EntityEditingTests
{
    [Fact]
    public void TrimOrExtendLineEndpointToLineBoundary()
    {
        var subject = new LineEntity(
            Guid.NewGuid(),
            Layer.Cut.Name,
            new Point2(0, 0),
            new Point2(8, 0));
        var boundary = new LineEntity(
            Guid.NewGuid(),
            Layer.Cut.Name,
            new Point2(10, -5),
            new Point2(10, 5));

        var success = EntityEditing.TryTrimOrExtendEndpoint(
            subject,
            new Point2(8, 0),
            boundary,
            new Point2(10, 0),
            out var replacement);

        Assert.True(success);
        var line = Assert.IsType<LineEntity>(replacement);
        Assert.Equal(new Point2(0, 0), line.Start);
        Assert.Equal(10.0, line.End.X, 9);
        Assert.Equal(0.0, line.End.Y, 9);
    }

    [Fact]
    public void TrimOrExtendLineEndpointCanUseLineBoundaryExtension()
    {
        var subject = new LineEntity(
            Guid.NewGuid(),
            Layer.Cut.Name,
            new Point2(0, 0),
            new Point2(8, 0));
        var boundary = new LineEntity(
            Guid.NewGuid(),
            Layer.Cut.Name,
            new Point2(10, 4),
            new Point2(10, 8));

        var success = EntityEditing.TryTrimOrExtendEndpoint(
            subject,
            new Point2(8, 0),
            boundary,
            new Point2(10, 4),
            out var replacement);

        Assert.True(success);
        var line = Assert.IsType<LineEntity>(replacement);
        Assert.Equal(10.0, line.End.X, 9);
        Assert.Equal(0.0, line.End.Y, 9);
    }

    [Fact]
    public void TrimRejectsLineExtension()
    {
        var subject = new LineEntity(
            Guid.NewGuid(),
            Layer.Cut.Name,
            new Point2(0, 0),
            new Point2(8, 0));
        var boundary = new LineEntity(
            Guid.NewGuid(),
            Layer.Cut.Name,
            new Point2(10, -5),
            new Point2(10, 5));

        var success = EntityEditing.TryTrimEndpoint(
            subject,
            new Point2(8, 0),
            boundary,
            new Point2(10, 0),
            out _);

        Assert.False(success);
    }

    [Fact]
    public void ExtendRejectsLineTrim()
    {
        var subject = new LineEntity(
            Guid.NewGuid(),
            Layer.Cut.Name,
            new Point2(0, 0),
            new Point2(12, 0));
        var boundary = new LineEntity(
            Guid.NewGuid(),
            Layer.Cut.Name,
            new Point2(10, -5),
            new Point2(10, 5));

        var success = EntityEditing.TryExtendEndpoint(
            subject,
            new Point2(12, 0),
            boundary,
            new Point2(10, 0),
            out _);

        Assert.False(success);
    }

    [Fact]
    public void TrimOrExtendArcEndpointToLineBoundary()
    {
        var subject = new ArcEntity(
            Guid.NewGuid(),
            Layer.Cut.Name,
            new Point2(0, 0),
            10,
            0,
            90,
            false);
        var boundary = new LineEntity(
            Guid.NewGuid(),
            Layer.Cut.Name,
            new Point2(5, -12),
            new Point2(5, 12));

        var success = EntityEditing.TryTrimOrExtendEndpoint(
            subject,
            subject.EndPoint,
            boundary,
            new Point2(5, 9),
            out var replacement);

        Assert.True(success);
        var arc = Assert.IsType<ArcEntity>(replacement);
        Assert.Equal(0.0, arc.StartAngleDeg, 9);
        Assert.Equal(60.0, arc.EndAngleDeg, 9);
    }
}
