using System.Net;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;

namespace detect.device.Utils;

public class IpAddressConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(IPAddress));
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteValue(value.ToString());
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return IPAddress.Parse((string)reader.Value);
    }
}

public class IpEndPointConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(IPEndPoint));
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var ep = (IPEndPoint)value;
        var jo = new JObject
        {
            { "Address", JToken.FromObject(ep.Address, serializer) },
            { "Port", ep.Port }
        };
        jo.WriteTo(writer);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var jo = JObject.Load(reader);
        var address = jo["Address"]?.ToObject<IPAddress>(serializer);
        var port = (int)jo["Port"]!;
        return new IPEndPoint(address!, port);
    }
}

public class JsonDateTimeConverter(string dateTimeFormat) : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
    {
        var dateTime = (DateTime)value!;
        writer.WriteValue(dateTime.ToString(dateTimeFormat));
    }

    public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
    {
        return DateTime.Parse((string)reader.Value!);
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(DateTime?);
    }
}


public static class JsonUtil
{
    /// <summary>
    /// 将对象序列化为json字符串
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="formatting"></param>
    /// <returns></returns>
    public static string SerializeObject(object obj, Formatting formatting = Formatting.None)
    {
        switch (obj)
        {
            case null:
                return null;
            case string s:
                return s;
        }

        var settings = new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver()
        };
        
        settings.Converters.Add(new JsonDateTimeConverter("yyyy-MM-dd HH:mm:ss"));
        settings.Converters.Add(new IpAddressConverter());
        settings.Converters.Add(new IpEndPointConverter());
        settings.Formatting = formatting;
        return JsonConvert.SerializeObject(obj, settings);
    }

    /// <summary>
    /// 将json字符串解析为对象
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="jsonStr"></param>
    /// <returns></returns>
    public static T DeserializeObject<T>(string jsonStr)
    {
        var settings = new JsonSerializerSettings();
        settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        settings.Converters.Add(new JsonDateTimeConverter("yyyy-MM-dd HH:mm:ss"));
        settings.Converters.Add(new IpAddressConverter());
        settings.Converters.Add(new IpEndPointConverter());
        return JsonConvert.DeserializeObject<T>(jsonStr, settings);
    }

    /// <summary>
    /// 将json字符串解析为对象
    /// </summary>
    /// <param name="jsonStr"></param>
    /// <param name="type"></param>
    /// <returns></returns>
    public static object DeserializeObject(string jsonStr, Type type)
    {
        var settings = new JsonSerializerSettings();
        settings.Converters.Add(new IpAddressConverter());
        settings.Converters.Add(new IpEndPointConverter());
        return JsonConvert.DeserializeObject(jsonStr, type, settings);
    }
}