using ZB.MOM.WW.ScadaBridge.Commons.Types;

namespace ZB.MOM.WW.ScadaBridge.Commons.Tests.Types;

public class ResultTests
{
    [Fact]
    public void Success_ShouldCreateSuccessfulResult()
    {
        var result = Result<int>.Success(42);

        Assert.True(result.IsSuccess);
        Assert.False(result.IsFailure);
        Assert.Equal(42, result.Value);
    }

    [Fact]
    public void Failure_ShouldCreateFailedResult()
    {
        var result = Result<int>.Failure("something went wrong");

        Assert.True(result.IsFailure);
        Assert.False(result.IsSuccess);
        Assert.Equal("something went wrong", result.Error);
    }

    [Fact]
    public void Value_OnFailure_ShouldThrow()
    {
        var result = Result<int>.Failure("error");

        Assert.Throws<InvalidOperationException>(() => result.Value);
    }

    [Fact]
    public void Error_OnSuccess_ShouldThrow()
    {
        var result = Result<int>.Success(42);

        Assert.Throws<InvalidOperationException>(() => result.Error);
    }

    [Fact]
    public void Match_OnSuccess_ShouldCallOnSuccess()
    {
        var result = Result<int>.Success(42);

        var output = result.Match(
            v => $"value={v}",
            e => $"error={e}");

        Assert.Equal("value=42", output);
    }

    [Fact]
    public void Match_OnFailure_ShouldCallOnFailure()
    {
        var result = Result<int>.Failure("bad");

        var output = result.Match(
            v => $"value={v}",
            e => $"error={e}");

        Assert.Equal("error=bad", output);
    }

    [Fact]
    public void Success_WithNullableReferenceType_ShouldWork()
    {
        var result = Result<string>.Success("hello");

        Assert.True(result.IsSuccess);
        Assert.Equal("hello", result.Value);
    }

    // ── Commons-011 regression: a failed Result must always carry a message ──

    [Fact]
    public void Failure_WithNullError_ShouldThrow()
    {
        Assert.Throws<ArgumentNullException>(() => Result<int>.Failure(null!));
    }

    [Theory]
    [InlineData("")]
    [InlineData("   ")]
    public void Failure_WithBlankError_ShouldThrow(string error)
    {
        Assert.Throws<ArgumentException>(() => Result<int>.Failure(error));
    }
}
