using Microsoft.Extensions.Configuration;
using System;
using System.IO;

namespace AvaloniaSerilogNoDI.Helpers;

public class AppSettings<TOption>
{
    #region Constructors 
    public AppSettings(IConfigurationSection configSection, string? key = null)
    {
        ConfigSection = configSection;

        // ReSharper disable once VirtualMemberCallInConstructor
        GetValue(key);
    }
    #endregion

    #region Properties
    protected static AppSettings<TOption>? AppSetting { get; private set; }

    // ReSharper disable once StaticMemberInGenericType
    protected static IConfigurationSection? ConfigSection { get; private set; }

    public TOption? Value { get; set; }
    #endregion

    #region Methods 
#pragma warning disable CA1000 // Do not declare static members on generic types
    public static TOption? Current(string section, string? key = null)
    {
        AppSetting = GetCurrentSettings(section, key);
        return AppSetting.Value;
    }


    public static AppSettings<TOption> GetCurrentSettings(string section, string? key = null)
#pragma warning restore CA1000 // Do not declare static members on generic types
    {
        string env = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT") ?? "Production";

        IConfigurationBuilder builder = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env}.json", optional: true, reloadOnChange: true)
            .AddEnvironmentVariables();

        IConfigurationRoot configuration = builder.Build();

        if (string.IsNullOrEmpty(section))
            section = "AppSettings"; // default

        AppSettings<TOption> settings = new AppSettings<TOption>(configuration.GetSection(section), key);

        return settings;
    }

    protected virtual void GetValue(string? key)
    {
        if (key is null)
        {
            // no key, so must be a class/strut object
            Value = Activator.CreateInstance<TOption>();
            ConfigSection!.Bind(Value);
            return;
        }

        Type optionType = typeof(TOption);

        if ((optionType == typeof(string) ||
             optionType == typeof(int) ||
             optionType == typeof(long) ||
             optionType == typeof(decimal) ||
             optionType == typeof(float) ||
             optionType == typeof(double)) 
            && ConfigSection != null)
        {
            // we must be retrieving a value
            Value = ConfigSection.GetValue<TOption>(key);
            return;
        }

        // Could not find a supported type
        throw new InvalidCastException($"Type {typeof(TOption).Name} is invalid");
    }

    #endregion
}