using ColaFlow.Modules.Mcp.Contracts.JsonRpc;
using ColaFlow.Modules.Mcp.Domain.Exceptions;
using FluentAssertions;

namespace ColaFlow.Modules.Mcp.Tests.Domain.Exceptions;

/// <summary>
/// Unit tests for MCP exception classes
/// </summary>
public class McpExceptionTests
{
    [Fact]
    public void McpParseException_ShouldHaveCorrectErrorCode()
    {
        // Arrange & Act
        var exception = new McpParseException("Invalid JSON");

        // Assert
        exception.ErrorCode.Should().Be(JsonRpcErrorCode.ParseError);
        exception.Message.Should().Be("Invalid JSON");
        exception.GetHttpStatusCode().Should().Be(400);
    }

    [Fact]
    public void McpInvalidRequestException_ShouldHaveCorrectErrorCode()
    {
        // Arrange & Act
        var exception = new McpInvalidRequestException("Missing required field");

        // Assert
        exception.ErrorCode.Should().Be(JsonRpcErrorCode.InvalidRequest);
        exception.Message.Should().Be("Missing required field");
        exception.GetHttpStatusCode().Should().Be(400);
    }

    [Fact]
    public void McpMethodNotFoundException_ShouldHaveCorrectErrorCode()
    {
        // Arrange & Act
        var exception = new McpMethodNotFoundException("unknown_method");

        // Assert
        exception.ErrorCode.Should().Be(JsonRpcErrorCode.MethodNotFound);
        exception.Message.Should().Be("Method not found: unknown_method");
        exception.GetHttpStatusCode().Should().Be(404);
    }

    [Fact]
    public void McpInvalidParamsException_ShouldHaveCorrectErrorCode()
    {
        // Arrange & Act
        var exception = new McpInvalidParamsException("Invalid parameter type");

        // Assert
        exception.ErrorCode.Should().Be(JsonRpcErrorCode.InvalidParams);
        exception.Message.Should().Be("Invalid parameter type");
        exception.GetHttpStatusCode().Should().Be(400);
    }

    [Fact]
    public void McpUnauthorizedException_ShouldHaveCorrectErrorCode()
    {
        // Arrange & Act
        var exception = new McpUnauthorizedException("Invalid API key");

        // Assert
        exception.ErrorCode.Should().Be(JsonRpcErrorCode.Unauthorized);
        exception.Message.Should().Be("Invalid API key");
        exception.GetHttpStatusCode().Should().Be(401);
    }

    [Fact]
    public void McpForbiddenException_ShouldHaveCorrectErrorCode()
    {
        // Arrange & Act
        var exception = new McpForbiddenException("Insufficient permissions");

        // Assert
        exception.ErrorCode.Should().Be(JsonRpcErrorCode.Forbidden);
        exception.Message.Should().Be("Insufficient permissions");
        exception.GetHttpStatusCode().Should().Be(403);
    }

    [Fact]
    public void McpNotFoundException_ShouldHaveCorrectErrorCode()
    {
        // Arrange & Act
        var exception = new McpNotFoundException("Task", "task-123");

        // Assert
        exception.ErrorCode.Should().Be(JsonRpcErrorCode.NotFound);
        exception.Message.Should().Be("Task not found: task-123");
        exception.GetHttpStatusCode().Should().Be(404);
    }

    [Fact]
    public void McpValidationException_ShouldHaveCorrectErrorCode()
    {
        // Arrange & Act
        var errorData = new { field = "name", error = "required" };
        var exception = new McpValidationException("Validation failed", errorData);

        // Assert
        exception.ErrorCode.Should().Be(JsonRpcErrorCode.ValidationFailed);
        exception.Message.Should().Be("Validation failed");
        exception.ErrorData.Should().Be(errorData);
        exception.GetHttpStatusCode().Should().Be(422);
    }

    [Fact]
    public void ToJsonRpcError_ShouldConvertToJsonRpcError()
    {
        // Arrange
        var errorData = new { detail = "test" };
        var exception = new McpValidationException("Test error", errorData);

        // Act
        var jsonRpcError = exception.ToJsonRpcError();

        // Assert
        jsonRpcError.Code.Should().Be((int)JsonRpcErrorCode.ValidationFailed);
        jsonRpcError.Message.Should().Be("Test error");
        jsonRpcError.Data.Should().Be(errorData);
    }

    [Fact]
    public void McpParseException_WithInnerException_ShouldPreserveInnerException()
    {
        // Arrange
        var innerException = new InvalidOperationException("Root cause");

        // Act
        var exception = new McpParseException("Parse failed", innerException);

        // Assert
        exception.InnerException.Should().Be(innerException);
        exception.InnerException.Message.Should().Be("Root cause");
    }

    [Fact]
    public void McpException_WithErrorData_ShouldPreserveErrorData()
    {
        // Arrange
        var errorData = new
        {
            field = "email",
            error = "invalid format",
            value = "not-an-email"
        };

        // Act
        var exception = new McpValidationException("Validation failed", errorData);

        // Assert
        exception.ErrorData.Should().NotBeNull();
        exception.ErrorData.Should().Be(errorData);
    }
}
