#if NET6_0_OR_GREATER
using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using Amazon.Lambda.Core;
using Amazon.Lambda.Serialization.SystemTextJson.Converters;
namespace Amazon.Lambda.Serialization.SystemTextJson
{
    /// 
    /// ILambdaSerializer implementation that supports the source generator support of System.Text.Json. To use this serializer define
    /// a partial JsonSerializerContext class with attributes for the types to be serialized.
    /// 
    /// [JsonSerializable(typeof(APIGatewayHttpApiV2ProxyRequest))]
    /// [JsonSerializable(typeof(APIGatewayHttpApiV2ProxyResponse))]
    /// public partial class APIGatewaySerializerContext : JsonSerializerContext
    /// {
    /// }
    /// 
    /// Register the serializer with the LambdaSerializer attribute specifying the defined JsonSerializerContext
    /// 
    /// [assembly: LambdaSerializer(typeof(SourceGeneratorLambdaJsonSerializer&ly;APIGatewayExampleImage.MyJsonContext>))]
    /// 
    /// When the class is compiled it will generate all of the JSON serialization code to convert between JSON and the list types. This
    /// will avoid any reflection based serialization.
    /// 
    /// 
    public class SourceGeneratorLambdaJsonSerializer<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TSGContext> : AbstractLambdaJsonSerializer, ILambdaSerializer where TSGContext : JsonSerializerContext
    {
        TSGContext _jsonSerializerContext;
        /// 
        /// The options used to serialize JSON object.
        /// 
        protected JsonSerializerOptions SerializerOptions { get; }
        /// 
        /// Constructs instance of serializer.
        /// 
        public SourceGeneratorLambdaJsonSerializer()
            : this(null, null)
        {
        }
        /// 
        /// Constructs instance of serializer with the option to customize the JsonSerializerOptions after the 
        /// Amazon.Lambda.Serialization.SystemTextJson's default settings have been applied.
        /// 
        /// 
        public SourceGeneratorLambdaJsonSerializer(Action customizer)
            : this(customizer, null)
        {
        }
        /// 
        /// Constructs instance of serializer with the option to customize the JsonWriterOptions after the 
        /// Amazon.Lambda.Serialization.SystemTextJson's default settings have been applied.
        /// 
        /// 
        public SourceGeneratorLambdaJsonSerializer(Action jsonWriterCustomizer)
            : this(null, jsonWriterCustomizer)
        {
        }
        /// 
        /// Constructs instance of serializer with the option to customize the JsonWriterOptions after the 
        /// Amazon.Lambda.Serialization.SystemTextJson's default settings have been applied.
        /// 
        /// 
        /// 
        public SourceGeneratorLambdaJsonSerializer(Action customizer, Action jsonWriterCustomizer)
            : base(jsonWriterCustomizer)
        {
            SerializerOptions = CreateDefaultJsonSerializationOptions();
            customizer?.Invoke(this.SerializerOptions);
            var constructor = typeof(TSGContext).GetConstructor(new Type[] { typeof(JsonSerializerOptions) });
            if(constructor == null)
            {
                throw new ApplicationException($"The serializer {typeof(TSGContext).FullName} is missing a constructor that takes in JsonSerializerOptions object");
            }
            _jsonSerializerContext = constructor.Invoke(new object[] { this.SerializerOptions }) as TSGContext;
        }
        /// 
        protected override void InternalSerialize(Utf8JsonWriter writer, T response)
        {
            var jsonTypeInfo = _jsonSerializerContext.GetTypeInfo(typeof(T)) as JsonTypeInfo;
            if (jsonTypeInfo == null)
            {
                throw new JsonSerializerException($"No JsonTypeInfo registered in {_jsonSerializerContext.GetType().FullName} for type {typeof(T).FullName}.");
            }
            JsonSerializer.Serialize(writer, response, jsonTypeInfo);
        }
        /// 
        protected override T InternalDeserialize(byte[] utf8Json)
        {
            var jsonTypeInfo = _jsonSerializerContext.GetTypeInfo(typeof(T)) as JsonTypeInfo;
            if (jsonTypeInfo == null)
            {
                throw new JsonSerializerException($"No JsonTypeInfo registered in {_jsonSerializerContext.GetType().FullName} for type {typeof(T).FullName}.");
            }
            return JsonSerializer.Deserialize(utf8Json, jsonTypeInfo);
        }
    }
}
#endif