using Kompas.Mcp.Core.Drawings;

namespace Kompas.Mcp.Tests;

[Trait("Category", "Unit")]
public sealed class DrawingValidationTests
{
    [Theory]
    [InlineData(null)]
    [InlineData("")]
    [InlineData("   ")]
    public void NormalizeModelPath_throws_on_empty(string? path)
        => Assert.Throws<ArgumentException>(() => DrawingValidation.NormalizeModelPath(path));

    [Theory]
    [InlineData(@"C:\m\part.step")]
    [InlineData(@"C:\m\part.txt")]
    [InlineData(@"C:\m\part")]
    public void NormalizeModelPath_throws_on_wrong_extension(string path)
        => Assert.Throws<ArgumentException>(() => DrawingValidation.NormalizeModelPath(path));

    [Theory]
    [InlineData(@"C:\m\part.m3d", ".m3d")]
    [InlineData(@"C:\m\frame.a3d", ".a3d")]
    [InlineData(@"  C:\m\part.M3D  ", ".m3d")]
    [InlineData(@"C:\модели\деталь.m3d", ".m3d")]   // кириллица в пути
    public void NormalizeModelPath_accepts_model_files(string path, string expectedExt)
    {
        var result = DrawingValidation.NormalizeModelPath(path);
        Assert.True(Path.IsPathFullyQualified(result));
        Assert.EndsWith(expectedExt, result, StringComparison.OrdinalIgnoreCase);
    }

    [Fact]
    public void NormalizeModelPath_preserves_cyrillic()
    {
        var result = DrawingValidation.NormalizeModelPath(@"C:\модели\деталь.m3d");
        Assert.Contains("деталь", result);
        Assert.Contains("модели", result);
    }

    [Theory]
    [InlineData(0)]
    [InlineData(-1)]
    [InlineData(double.NaN)]
    [InlineData(double.PositiveInfinity)]
    public void RequireScale_throws_on_non_positive_or_non_finite(double scale)
        => Assert.Throws<ArgumentOutOfRangeException>(() => DrawingValidation.RequireScale(scale));

    [Theory]
    [InlineData(1.0)]
    [InlineData(0.5)]
    [InlineData(2.0)]
    public void RequireScale_accepts_positive(double scale)
        => Assert.Null(Record.Exception(() => DrawingValidation.RequireScale(scale)));

    [Fact]
    public void RequireFiniteCoords_throws_on_non_finite()
    {
        Assert.Throws<ArgumentException>(() => DrawingValidation.RequireFiniteCoords(0, double.NaN));
        Assert.Throws<ArgumentException>(() => DrawingValidation.RequireFiniteCoords(double.PositiveInfinity));
        Assert.Null(Record.Exception(() => DrawingValidation.RequireFiniteCoords(0, 1, -5, 40)));
    }

    [Fact]
    public void RequireDistinctPoints_throws_on_coincident()
    {
        Assert.Throws<ArgumentException>(() => DrawingValidation.RequireDistinctPoints(10, 20, 10, 20));
        Assert.Null(Record.Exception(() => DrawingValidation.RequireDistinctPoints(0, 0, 40, 0)));
    }

    [Theory]
    [InlineData(0)]
    [InlineData(-5)]
    [InlineData(double.NaN)]
    [InlineData(double.PositiveInfinity)]
    public void RequirePositiveRadius_throws_on_non_positive_or_non_finite(double radius)
        => Assert.Throws<ArgumentOutOfRangeException>(() => DrawingValidation.RequirePositiveRadius(radius));

    [Fact]
    public void RequirePositiveRadius_accepts_positive()
        => Assert.Null(Record.Exception(() => DrawingValidation.RequirePositiveRadius(15)));

    [Theory]
    [InlineData(null)]
    [InlineData("")]
    [InlineData("   ")]
    public void RequireNonEmptyText_throws_on_empty(string? text)
        => Assert.Throws<ArgumentException>(() => DrawingValidation.RequireNonEmptyText(text, "text"));

    [Fact]
    public void RequireNonEmptyText_accepts_non_empty()
        => Assert.Null(Record.Exception(() => DrawingValidation.RequireNonEmptyText("Ra 1.6", "text")));

    [Theory]
    [InlineData(0, 300)]
    [InlineData(500, 0)]
    [InlineData(-1, 300)]
    [InlineData(double.NaN, 300)]
    [InlineData(500, double.PositiveInfinity)]
    public void ValidateFormatDimensions_user_throws_on_non_positive_or_non_finite(double w, double h)
        => Assert.Throws<ArgumentOutOfRangeException>(
            () => DrawingValidation.ValidateFormatDimensions(PaperFormat.User, w, h));

    [Fact]
    public void ValidateFormatDimensions_user_accepts_positive()
        => Assert.Null(Record.Exception(
            () => DrawingValidation.ValidateFormatDimensions(PaperFormat.User, 500, 300)));

    [Theory]
    [InlineData(500, 0)]
    [InlineData(0, 300)]
    [InlineData(500, 300)]
    public void ValidateFormatDimensions_standard_throws_when_dimensions_given(double w, double h)
        => Assert.Throws<ArgumentException>(
            () => DrawingValidation.ValidateFormatDimensions(PaperFormat.A3, w, h));

    [Fact]
    public void ValidateFormatDimensions_standard_accepts_zero_dimensions()
        => Assert.Null(Record.Exception(
            () => DrawingValidation.ValidateFormatDimensions(PaperFormat.A3, 0, 0)));
}
