using System;
using System.Runtime.InteropServices;
using ZB.MOM.WW.MxGateway.Contracts.Proto;
using ZB.MOM.WW.MxGateway.Worker.Conversion;

namespace ZB.MOM.WW.MxGateway.Worker.Tests.Conversion;

/// <summary>
/// Tests for <see cref="HResultConverter"/>.
/// </summary>
public sealed class HResultConverterTests
{
    private readonly HResultConverter _converter = new();

    /// <summary>
    /// Verifies that Convert captures the HResult from a COM exception.
    /// </summary>
    [Fact]
    public void Convert_WithComException_CapturesExceptionHResult()
    {
        COMException exception = new("Sensitive provider text should not be copied.", unchecked((int)0x80070057));

        HResultConversion converted = _converter.Convert(exception);

        Assert.Equal(unchecked((int)0x80070057), converted.HResult);
        Assert.Equal(ProtocolStatusCode.MxaccessFailure, converted.ProtocolStatus.Code);
        Assert.Contains("0x80070057", converted.ProtocolStatus.Message);
        Assert.Contains(typeof(COMException).FullName!, converted.DiagnosticMessage);
        Assert.DoesNotContain("Sensitive provider text", converted.DiagnosticMessage);
    }

    /// <summary>
    /// Verifies that CreateProtocolStatus returns OK for a success HResult.
    /// </summary>
    [Fact]
    public void CreateProtocolStatus_WithSuccessHResult_ReturnsOk()
    {
        ProtocolStatus status = _converter.CreateProtocolStatus(0);

        Assert.Equal(ProtocolStatusCode.Ok, status.Code);
        Assert.Equal("HRESULT 0x00000000", status.Message);
    }

    /// <summary>
    /// Verifies that Convert captures the HResult from a non-COM exception.
    /// </summary>
    [Fact]
    public void Convert_WithNonComException_CapturesExceptionHResult()
    {
        InvalidOperationException exception = new("do not include this");

        HResultConversion converted = _converter.Convert(exception);

        Assert.Equal(exception.HResult, converted.HResult);
        Assert.Equal(ProtocolStatusCode.MxaccessFailure, converted.ProtocolStatus.Code);
        Assert.Contains("0x", converted.DiagnosticMessage);
        Assert.DoesNotContain("do not include this", converted.DiagnosticMessage);
    }
}
