using Newtonsoft.Json;

namespace Pilz.Data;

#pragma warning disable CA2231

[Serializable]
public struct PropertyValue<T>(T value) where T : struct
{
    [JsonProperty(PropertyName = "HasValue")]
    private readonly bool hasValue = true; // Do not rename (binary serialization)
    [JsonProperty(PropertyName = "Value")]
    internal T value = value; // Do not rename (binary serialization) or make readonly (can be mutated in ToString, etc.)

    [JsonIgnore]
    public static PropertyValue<T> Empty => default;

    [JsonIgnore]
    public readonly bool HasValue
    {
        get => hasValue;
    }

    [JsonIgnore]
    public readonly T Value
    {
        get
        {
            if (!hasValue)
                throw new InvalidOperationException("No value");
            return value;
        }
    }

    public readonly T GetValueOrDefault() => value;

    public readonly T GetValueOrDefault(T defaultValue) =>
        hasValue ? value : defaultValue;

    public override readonly bool Equals(object? other)
    {
        if (!hasValue) return other == null;
        if (other == null) return false;
        return value.Equals(other);
    }

    public override readonly int GetHashCode() => hasValue ? value.GetHashCode() : 0;

    public override readonly string? ToString() => hasValue ? value.ToString() : string.Empty;

    public static implicit operator PropertyValue<T>(T value) => new(value);

    public static explicit operator T(PropertyValue<T> value) => value.Value;
}