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

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

public sealed class HResultConverter
{
    /// <summary>Converts an exception to an HResult conversion with protocol status and diagnostic message.</summary>
    /// <param name="exception">Exception to convert.</param>
    /// <returns>Conversion result with HResult, protocol status, and diagnostics.</returns>
    public HResultConversion Convert(Exception exception)
    {
        if (exception is null)
        {
            throw new ArgumentNullException(nameof(exception));
        }

        int hresult = exception is COMException comException
            ? comException.ErrorCode
            : exception.HResult;

        return new HResultConversion(
            hresult,
            CreateProtocolStatus(hresult, exception),
            CreateSafeDiagnosticMessage(exception));
    }

    /// <summary>Creates a protocol status from an HResult code and optional exception.</summary>
    /// <param name="hresult">HResult error code.</param>
    /// <param name="exception">Exception providing additional context.</param>
    /// <returns>Protocol status with mapped code and message.</returns>
    public ProtocolStatus CreateProtocolStatus(
        int hresult,
        Exception? exception = null)
    {
        return new ProtocolStatus
        {
            Code = hresult == 0 ? ProtocolStatusCode.Ok : ProtocolStatusCode.MxaccessFailure,
            Message = exception is null
                ? FormatHResult(hresult)
                : $"{exception.GetType().Name}: {FormatHResult(hresult)}",
        };
    }

    private static string CreateSafeDiagnosticMessage(Exception exception)
    {
        return $"{exception.GetType().FullName}: {FormatHResult(exception.HResult)}";
    }

    private static string FormatHResult(int hresult)
    {
        return $"HRESULT 0x{unchecked((uint)hresult):X8}";
    }
}
