using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace StartupHelpers;

public static class EnvironmentDiagnostics
{
    public static void LogEnvironmentSettings(ILogger logger, IConfiguration configuration, IWebHostEnvironment environment)
    {
        LogEnvironmentSettingsCore(logger, configuration, environment.ApplicationName, environment.EnvironmentName,
            environment.ContentRootPath, environment.WebRootPath);
    }

    public static void LogEnvironmentSettings(ILogger logger, IConfiguration configuration, IHostEnvironment environment)
    {
        LogEnvironmentSettingsCore(logger, configuration, environment.ApplicationName, environment.EnvironmentName,
            environment.ContentRootPath, webRootPath: null);
    }

    private static void LogEnvironmentSettingsCore(
        ILogger logger,
        IConfiguration configuration,
        string applicationName,
        string environmentName,
        string contentRootPath,
        string? webRootPath)
    {
        logger.LogInformation("==================== ENVIRONMENT SETTINGS ====================");
        logger.LogInformation("Application Name: {ApplicationName}", applicationName);
        logger.LogInformation("Environment Name: {EnvironmentName}", environmentName);
        logger.LogInformation("Content Root Path: {ContentRootPath}", contentRootPath);
        if (!string.IsNullOrEmpty(webRootPath))
        {
            logger.LogInformation("Web Root Path: {WebRootPath}", webRootPath);
        }

        logger.LogInformation("-------------- Environment Variables --------------");
        var envVars = Environment.GetEnvironmentVariables();
        var sortedEnvVars = new SortedDictionary<string, string?>();

        foreach (System.Collections.DictionaryEntry entry in envVars)
        {
            var key = entry.Key?.ToString() ?? string.Empty;
            var value = entry.Value?.ToString() ?? string.Empty;

            if (IsSensitiveKey(key))
            {
                value = MaskValueWithLastChars(value);
            }

            sortedEnvVars[key] = value;
        }

        foreach (var kvp in sortedEnvVars)
        {
            logger.LogInformation("  {Key} = {Value}", kvp.Key, kvp.Value);
        }

        logger.LogInformation("-------------- Configuration Settings --------------");
        LogConfigurationRecursive(logger, configuration.GetChildren(), string.Empty);
        logger.LogInformation("===========================================================");
    }

    private static void LogConfigurationRecursive(ILogger logger, IEnumerable<IConfigurationSection> sections, string prefix)
    {
        foreach (var section in sections)
        {
            var key = string.IsNullOrEmpty(prefix) ? section.Key : $"{prefix}:{section.Key}";

            if (section.Value != null)
            {
                var value = section.Value;
                if (IsSensitiveKey(key))
                {
                    value = MaskValueWithLastChars(value);
                }

                logger.LogInformation("  {Key} = {Value}", key, value);
            }

            if (section.GetChildren().Any())
            {
                LogConfigurationRecursive(logger, section.GetChildren(), key);
            }
        }
    }

    private static bool IsSensitiveKey(string key)
    {
        return key.Contains("Password", StringComparison.OrdinalIgnoreCase)
               || key.Contains("Secret", StringComparison.OrdinalIgnoreCase)
               || key.Contains("Token", StringComparison.OrdinalIgnoreCase)
               || key.Contains("Key", StringComparison.OrdinalIgnoreCase)
               || key.Contains("ConnectionString", StringComparison.OrdinalIgnoreCase);
    }

    private static string MaskValueWithLastChars(string value)
    {
        if (string.IsNullOrEmpty(value))
        {
            return "***NOT SET***";
        }

        if (value.Length <= 4)
        {
            return "***MASKED***";
        }

        var lastChars = value[^4..];
        return $"***MASKED***...{lastChars}";
    }
}
