namespace ByteBard.AsyncAPI.Readers
{
    using System;
    using ByteBard.AsyncAPI.Extensions;
    using ByteBard.AsyncAPI.Models;
    using ByteBard.AsyncAPI.Readers.ParseNodes;

    /// <summary>
    /// Class containing logic to deserialize AsyncApi document into
    /// runtime AsyncApi object model.
    /// </summary>
    internal static partial class AsyncApiV3Deserializer
    {
        private static readonly FixedFieldMap<AsyncApiSecurityScheme> securitySchemeFixedFields =
            new()
            {
                {
                    "type", (o, n) => { o.Type = n.GetScalarValue().GetEnumFromDisplayName<SecuritySchemeType>(); }
                },
                {
                    "description", (o, n) => { o.Description = n.GetScalarValue(); }
                },
                {
                    "name", (o, n) => { o.Name = n.GetScalarValue(); }
                },
                {
                    "in", (o, n) => { o.In = n.GetScalarValue().GetEnumFromDisplayName<ParameterLocation>(); }
                },
                {
                    "scheme", (o, n) => { o.Scheme = n.GetScalarValue(); }
                },
                {
                    "bearerFormat", (o, n) => { o.BearerFormat = n.GetScalarValue(); }
                },
                {
                    "flows", (o, n) => { o.Flows = LoadOAuthFlows(n); }
                },
                {
                    "openIdConnectUrl",
                    (o, n) => { o.OpenIdConnectUrl = new Uri(n.GetScalarValue(), UriKind.RelativeOrAbsolute); }
                },
                {
                    "scopes",
                    (o, n) => { o.Scopes = n.CreateSimpleSet(n2 => n2.GetScalarValue()); }
                },
            };

        private static readonly PatternFieldMap<AsyncApiSecurityScheme> securitySchemePatternFields =
            new()
            {
                { s => s.StartsWith("x-"), (o, p, n) => o.AddExtension(p, LoadExtension(p, n)) },
            };

        public static AsyncApiSecurityScheme LoadSecurityScheme(ParseNode node)
        {
            var mapNode = node.CheckMapNode("securityScheme");
            var pointer = mapNode.GetReferencePointer();
            if (pointer != null)
            {
                return new AsyncApiSecuritySchemeReference(pointer);
            }

            var securityScheme = new AsyncApiSecurityScheme();
            foreach (var property in mapNode)
            {
                property.ParseField(securityScheme, securitySchemeFixedFields, securitySchemePatternFields);
            }

            return securityScheme;
        }
    }
}
