using Newtonsoft.Json;

namespace Pilz.Json;

public class AppVersionStringJsonConverter(bool serializeAsObject) : JsonConverter
{
    public AppVersionStringJsonConverter() : this(false)
    {
    }

    /// <summary>
    /// Writes the JSON representation of the object.
    /// </summary>
    /// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
    /// <param name="value">The value.</param>
    /// <param name="serializer">The calling serializer.</param>
    public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
    {
        if (value == null)
        {
            writer.WriteNull();
            return;
        }

        if (serializeAsObject || value is not AppVersion appVersion)
            writer.WriteValue(value);
        else
            writer.WriteValue(appVersion.ToString());
    }

    /// <summary>
    /// Reads the JSON representation of the object.
    /// </summary>
    /// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
    /// <param name="objectType">Type of the object.</param>
    /// <param name="existingValue">The existing value of object being read.</param>
    /// <param name="serializer">The calling serializer.</param>
    /// <returns>The object value.</returns>
    public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;

        try
        {
            if (reader.TokenType == JsonToken.String)
            {
                var strValue = reader.Value?.ToString();

                if (string.IsNullOrWhiteSpace(strValue))
                    return null;

                return AppVersion.Parse(strValue);

            }

            if (reader.TokenType == JsonToken.StartObject)
                return serializer.Deserialize<AppVersion>(reader);
        }
        catch (Exception ex)
        {
            throw new JsonSerializationException("Error converting value {0} to type '{1}'.", ex);
        }

        // we don't actually expect to get here.
        throw new JsonSerializationException("Unexpected token {0} when parsing app version.");
    }

    /// <summary>
    /// Determines whether this instance can convert the specified object type.
    /// </summary>
    /// <param name="objectType">Type of the object.</param>
    /// <returns>
    /// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
    /// </returns>
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(AppVersion);
    }
}
