// Copyright © Amer Koleci and Contributors.
// Licensed under the MIT License (MIT). See LICENSE in the repository root for more information.

using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;

namespace Win32;

public readonly partial struct HResult : IComparable, IComparable<HResult>, IEquatable<HResult>, IFormattable
{
    public readonly int Value;

    public HResult(int value)
    {
        Value = value;
    }

    public static bool operator ==(HResult left, HResult right) => left.Value == right.Value;

    public static bool operator !=(HResult left, HResult right) => left.Value != right.Value;

    public static bool operator <(HResult left, HResult right) => left.Value < right.Value;

    public static bool operator <=(HResult left, HResult right) => left.Value <= right.Value;

    public static bool operator >(HResult left, HResult right) => left.Value > right.Value;

    public static bool operator >=(HResult left, HResult right) => left.Value >= right.Value;

    public static implicit operator HResult(byte value) => new HResult(value);

    public static explicit operator byte(HResult value) => (byte)(value.Value);

    public static implicit operator HResult(short value) => new HResult(value);

    public static explicit operator short(HResult value) => (short)(value.Value);

    public static implicit operator HResult(int value) => new HResult(value);

    public static implicit operator int(HResult value) => value.Value;

    public static explicit operator HResult(long value) => new HResult(unchecked((int)(value)));

    public static implicit operator long(HResult value) => value.Value;

    public static explicit operator HResult(nint value) => new HResult(unchecked((int)(value)));

    public static implicit operator nint(HResult value) => value.Value;

    public static implicit operator HResult(sbyte value) => new HResult(value);

    public static explicit operator sbyte(HResult value) => (sbyte)(value.Value);

    public static implicit operator HResult(ushort value) => new HResult(value);

    public static explicit operator ushort(HResult value) => (ushort)(value.Value);

    public static explicit operator HResult(uint value) => new HResult(unchecked((int)(value)));

    public static explicit operator uint(HResult value) => (uint)(value.Value);

    public static explicit operator HResult(ulong value) => new HResult(unchecked((int)(value)));

    public static explicit operator ulong(HResult value) => (ulong)(value.Value);

    public static explicit operator HResult(nuint value) => new HResult(unchecked((int)(value)));

    public static explicit operator nuint(HResult value) => (nuint)(value.Value);

    public int CompareTo(object? obj)
    {
        if (obj is HResult other)
        {
            return CompareTo(other);
        }

        return (obj is null) ? 1 : throw new ArgumentException("obj is not an instance of HResult.");
    }

    public int CompareTo(HResult other) => Value.CompareTo(other.Value);

    public override bool Equals(object? obj) => (obj is HResult other) && Equals(other);

    public bool Equals(HResult other) => Value.Equals(other.Value);

    public override int GetHashCode() => Value.GetHashCode();

    public override string ToString() => Value.ToString("X8");

    public string ToString(string? format, IFormatProvider? formatProvider) => Value.ToString(format, formatProvider);

    public bool Failure => Value < 0;

    public bool Success => Value >= 0;
}
