using System.Text.Json;

namespace ScadaLink.InboundAPI.Tests;

/// <summary>
/// WP-2: Tests for parameter validation — type checking, required fields, extended type system.
/// </summary>
public class ParameterValidatorTests
{
    [Fact]
    public void NoDefinitions_NoBody_ReturnsValid()
    {
        var result = ParameterValidator.Validate(null, null);
        Assert.True(result.IsValid);
        Assert.Empty(result.Parameters);
    }

    [Fact]
    public void EmptyDefinitions_ReturnsValid()
    {
        var result = ParameterValidator.Validate(null, "[]");
        Assert.True(result.IsValid);
    }

    [Fact]
    public void RequiredParameterMissing_ReturnsInvalid()
    {
        var definitions = JsonSerializer.Serialize(new[]
        {
            new { Name = "value", Type = "Integer", Required = true }
        });

        var result = ParameterValidator.Validate(null, definitions);
        Assert.False(result.IsValid);
        Assert.Contains("Missing required parameter", result.ErrorMessage);
    }

    [Fact]
    public void BodyNotObject_ReturnsInvalid()
    {
        var definitions = JsonSerializer.Serialize(new[]
        {
            new { Name = "value", Type = "String", Required = true }
        });

        using var doc = JsonDocument.Parse("\"just a string\"");
        var result = ParameterValidator.Validate(doc.RootElement.Clone(), definitions);
        Assert.False(result.IsValid);
        Assert.Contains("must be a JSON object", result.ErrorMessage);
    }

    [Theory]
    [InlineData("Boolean", "true", true)]
    [InlineData("Integer", "42", (long)42)]
    [InlineData("Float", "3.14", 3.14)]
    [InlineData("String", "\"hello\"", "hello")]
    public void ValidTypeCoercion_Succeeds(string type, string jsonValue, object expected)
    {
        var definitions = JsonSerializer.Serialize(new[]
        {
            new { Name = "val", Type = type, Required = true }
        });

        using var doc = JsonDocument.Parse($"{{\"val\": {jsonValue}}}");
        var result = ParameterValidator.Validate(doc.RootElement.Clone(), definitions);
        Assert.True(result.IsValid);
        Assert.Equal(expected, result.Parameters["val"]);
    }

    [Fact]
    public void WrongType_ReturnsInvalid()
    {
        var definitions = JsonSerializer.Serialize(new[]
        {
            new { Name = "count", Type = "Integer", Required = true }
        });

        using var doc = JsonDocument.Parse("{\"count\": \"not a number\"}");
        var result = ParameterValidator.Validate(doc.RootElement.Clone(), definitions);
        Assert.False(result.IsValid);
        Assert.Contains("must be an Integer", result.ErrorMessage);
    }

    [Fact]
    public void ObjectType_Parsed()
    {
        var definitions = JsonSerializer.Serialize(new[]
        {
            new { Name = "data", Type = "Object", Required = true }
        });

        using var doc = JsonDocument.Parse("{\"data\": {\"key\": \"value\"}}");
        var result = ParameterValidator.Validate(doc.RootElement.Clone(), definitions);
        Assert.True(result.IsValid);
        Assert.IsType<Dictionary<string, object?>>(result.Parameters["data"]);
    }

    [Fact]
    public void ListType_Parsed()
    {
        var definitions = JsonSerializer.Serialize(new[]
        {
            new { Name = "items", Type = "List", Required = true }
        });

        using var doc = JsonDocument.Parse("{\"items\": [1, 2, 3]}");
        var result = ParameterValidator.Validate(doc.RootElement.Clone(), definitions);
        Assert.True(result.IsValid);
        Assert.IsType<List<object?>>(result.Parameters["items"]);
    }

    [Fact]
    public void OptionalParameter_MissingBody_ReturnsValid()
    {
        var definitions = JsonSerializer.Serialize(new[]
        {
            new { Name = "optional", Type = "String", Required = false }
        });

        var result = ParameterValidator.Validate(null, definitions);
        Assert.True(result.IsValid);
    }

    [Fact]
    public void UnknownType_ReturnsInvalid()
    {
        var definitions = JsonSerializer.Serialize(new[]
        {
            new { Name = "val", Type = "CustomType", Required = true }
        });

        using var doc = JsonDocument.Parse("{\"val\": \"test\"}");
        var result = ParameterValidator.Validate(doc.RootElement.Clone(), definitions);
        Assert.False(result.IsValid);
        Assert.Contains("Unknown parameter type", result.ErrorMessage);
    }
}
