// <auto-generated/>

#nullable enable annotations
#nullable disable warnings

// Suppress warnings about [Obsolete] member usage in generated code.
#pragma warning disable CS0612, CS0618

namespace System.Runtime.CompilerServices
{
    using System;
    using System.CodeDom.Compiler;

    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
    file sealed class InterceptsLocationAttribute : Attribute
    {
        public InterceptsLocationAttribute(string filePath, int line, int column)
        {
        }
    }
}

namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
{
    using Microsoft.Extensions.Configuration;
    using System;
    using System.CodeDom.Compiler;
    using System.Globalization;
    using System.Runtime.CompilerServices;

    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
    file static class BindingExtensions
    {
        #region IConfiguration extensions.
        /// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
        [InterceptsLocation(@"src-0.cs", 10, 16)]
        public static T? Get<T>(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T));

        /// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
        [InterceptsLocation(@"src-0.cs", 12, 16)]
        public static T? Get<T>(this IConfiguration configuration, Action<BinderOptions>? configureOptions) => (T?)(GetCore(configuration, typeof(T), configureOptions) ?? default(T));

        /// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
        [InterceptsLocation(@"src-0.cs", 11, 16)]
        public static object? Get(this IConfiguration configuration, Type type) => GetCore(configuration, type, configureOptions: null);

        /// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
        [InterceptsLocation(@"src-0.cs", 13, 16)]
        public static object? Get(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions) => GetCore(configuration, type, configureOptions);
        #endregion IConfiguration extensions.

        #region Core binding extensions.
        public static object? GetCore(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions)
        {
            if (configuration is null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }

            BinderOptions? binderOptions = GetBinderOptions(configureOptions);

            if (!HasValueOrChildren(configuration))
            {
                return null;
            }

            if (type == typeof(int))
            {
                if (configuration is not IConfigurationSection section)
                {
                    throw new InvalidOperationException();
                }
                if (section.Value is string value)
                {
                    return ParseInt(value, () => section.Path);
                }
            }
            else if (type == typeof(string))
            {
                if (configuration is not IConfigurationSection section)
                {
                    throw new InvalidOperationException();
                }
                return section.Value;
            }
            else if (type == typeof(float))
            {
                if (configuration is not IConfigurationSection section)
                {
                    throw new InvalidOperationException();
                }
                if (section.Value is string value)
                {
                    return ParseFloat(value, () => section.Path);
                }
            }
            else if (type == typeof(double))
            {
                if (configuration is not IConfigurationSection section)
                {
                    throw new InvalidOperationException();
                }
                if (section.Value is string value)
                {
                    return ParseDouble(value, () => section.Path);
                }
            }

            throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
        }

        public static bool HasValueOrChildren(IConfiguration configuration)
        {
            if ((configuration as IConfigurationSection)?.Value is not null)
            {
                return true;
            }
            return AsConfigWithChildren(configuration) is not null;
        }

        public static IConfiguration? AsConfigWithChildren(IConfiguration configuration)
        {
            foreach (IConfigurationSection _ in configuration.GetChildren())
            {
                return configuration;
            }
            return null;
        }

        public static BinderOptions? GetBinderOptions(Action<BinderOptions>? configureOptions)
        {
            if (configureOptions is null)
            {
                return null;
            }
        
            BinderOptions binderOptions = new();
            configureOptions(binderOptions);
        
            if (binderOptions.BindNonPublicProperties)
            {
                throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
            }
        
            return binderOptions;
        }

        public static int ParseInt(string value, Func<string?> getPath)
        {
            try
            {
                return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture);
            }
            catch (Exception exception)
            {
                throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
            }
        }

        public static float ParseFloat(string value, Func<string?> getPath)
        {
            try
            {
                return float.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture);
            }
            catch (Exception exception)
            {
                throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(float)}'.", exception);
            }
        }

        public static double ParseDouble(string value, Func<string?> getPath)
        {
            try
            {
                return double.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture);
            }
            catch (Exception exception)
            {
                throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(double)}'.", exception);
            }
        }
        #endregion Core binding extensions.
    }
}
