using System.Collections.Specialized;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace EasyDevCore.Remote.HttpAccess
{
	/// <summary>
	/// ISerializer implementation that uses System.Text.Json
	/// Default serializer used in calls to GetJson, etc.
	/// </summary>
	public class TextJsonSerializer : ISerializer
	{
        private static JsonSerializerOptions _defaultOptions;
        private JsonSerializerOptions _options;

        private JsonSerializerOptions _serializerOptions => _options ?? _defaultOptions;


        /// <summary>
        /// Initializes a new instance of the <see cref="TextJsonSerializer"/> class.
        /// </summary>
        public TextJsonSerializer()
		{
            if (_defaultOptions == null)
            {
                _defaultOptions = new JsonSerializerOptions()
                {
					PropertyNameCaseInsensitive = true,
					WriteIndented = true,
                };
                _defaultOptions.Converters.Add(new JsonStringEnumConverter());
                _defaultOptions.Converters.Add(new JsonDateTimeConverter());
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="TextJsonSerializer"/> class.
        /// </summary>
        /// <param name="options">The options.</param>
        public TextJsonSerializer(JsonSerializerOptions options)
		{
			_options = options;
		}
        
		/// <summary>
        /// Serializes the specified object.
        /// </summary>
        /// <param name="obj">The object.</param>
        /// <returns></returns>
        public string Serialize(object obj)
		{
			return JsonSerializer.Serialize(obj, _serializerOptions);
		}

		/// <summary>
		/// Serializes the specified object.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="obj">The object.</param>
		/// <returns></returns>
		public string Serialize<T>(T obj)
		{
			return JsonSerializer.Serialize(obj, _serializerOptions);
		}

		/// <summary>
		/// Deserializes the specified s.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="s">The s.</param>
		/// <returns></returns>
		public T Deserialize<T>(string s)
		{
			return JsonSerializer.Deserialize<T>(s, _serializerOptions);
		}

		/// <summary>
		/// Deserializes the specified stream.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="stream">The stream.</param>
		/// <returns></returns>
		public T Deserialize<T>(Stream stream)
		{
			return JsonSerializer.Deserialize<T>(stream, _serializerOptions);
		}

        /// <summary>
        /// Deserializes the asynchronous.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="stream">The stream.</param>
        /// <returns></returns>
        public async Task<T> DeserializeAsync<T>(Stream stream)
        {
            return await JsonSerializer.DeserializeAsync<T>(stream, _serializerOptions).ConfigureAwait(false);

        }
    }
}
