namespace Engine.Util;

public readonly struct NullableObject<T>(T? parValue) : IEquatable<NullableObject<T>>
  where T : class
{
  public bool IsNull => Value == null;
  public T? Value { get; } = parValue;

  public NullableObject() : this(null)
  {
  }

  public static implicit operator T?(NullableObject<T> parNullableObject)
  {
    return parNullableObject.Value;
  }

  public static implicit operator NullableObject<T>(T? parValue)
  {
    return new NullableObject<T>(parValue);
  }

  public override string ToString()
  {
    return Value?.ToString() ?? "null";
  }

  public override bool Equals(object? parObj)
  {
    return parObj is NullableObject<T> other && Equals(other);
  }

  public override int GetHashCode()
  {
    if (IsNull)
    {
      return 0;
    }

    var hashCode = Value!.GetHashCode();

    if (hashCode >= 0)
    {
      hashCode += 1;
    }

    return hashCode;
  }

  public bool Equals(NullableObject<T> parOther)
  {
    return EqualityComparer<T?>.Default.Equals(Value, parOther.Value);
  }

  public static bool operator ==(NullableObject<T> parLeft, NullableObject<T> parRight)
  {
    return parLeft.Equals(parRight);
  }

  public static bool operator !=(NullableObject<T> parLeft, NullableObject<T> parRight)
  {
    return !(parLeft == parRight);
  }
}