using System.Text.Json;

namespace ZB.MOM.WW.ScadaBridge.CLI;

/// <summary>
/// Resolved CLI configuration combining config file values, environment variable overrides, and per-invocation credentials.
/// </summary>
public class CliConfig
{
    /// <summary>Base URL of the ScadaBridge Management API (e.g. http://localhost:9000).</summary>
    public string? ManagementUrl { get; set; }
    /// <summary>Default output format for CLI commands; defaults to "json".</summary>
    public string DefaultFormat { get; set; } = "json";

    /// <summary>
    /// LDAP username from the <c>SCADABRIDGE_USERNAME</c> environment variable, if set.
    /// Credentials are intentionally only sourced from environment variables (or the
    /// command line) — never from the config file — so they are not persisted to disk.
    /// </summary>
    public string? Username { get; set; }

    /// <summary>
    /// LDAP password from the <c>SCADABRIDGE_PASSWORD</c> environment variable, if set.
    /// Provides a safer alternative to <c>--password</c>, which leaks into process
    /// listings and shell history.
    /// </summary>
    public string? Password { get; set; }

    /// <summary>
    /// Loads CLI configuration by merging the config file, environment variables, and credential env vars.
    /// </summary>
    /// <returns>A populated <see cref="CliConfig"/> instance.</returns>
    public static CliConfig Load()
    {
        var config = new CliConfig();

        // Load from config file
        var configPath = Path.Combine(
            Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
            ".scadabridge", "config.json");
        if (File.Exists(configPath))
        {
            // A malformed (`JsonException`), unreadable
            // (`UnauthorizedAccessException`), or otherwise faulted
            // (`IOException`) config file must not crash the CLI before any
            // command runs — even a command that supplies everything via
            // --url/--username/--password/--format on the command line still
            // calls Load() and would otherwise inherit the fault. Warn once on
            // stderr and fall through to the env-var + command-line precedence
            // chain with default settings.
            try
            {
                var json = File.ReadAllText(configPath);
                var fileConfig = JsonSerializer.Deserialize<CliConfigFile>(json,
                    new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
                if (fileConfig != null)
                {
                    if (!string.IsNullOrEmpty(fileConfig.ManagementUrl))
                        config.ManagementUrl = fileConfig.ManagementUrl;
                    if (!string.IsNullOrEmpty(fileConfig.DefaultFormat))
                        config.DefaultFormat = fileConfig.DefaultFormat;
                }
            }
            catch (Exception ex) when (ex is JsonException || ex is IOException || ex is UnauthorizedAccessException)
            {
                Console.Error.WriteLine(
                    $"warning: ignoring malformed or unreadable {configPath}: {ex.Message}");
            }
        }

        // Override from environment variables
        var envUrl = Environment.GetEnvironmentVariable("SCADABRIDGE_MANAGEMENT_URL");
        if (!string.IsNullOrEmpty(envUrl))
            config.ManagementUrl = envUrl;

        var envFormat = Environment.GetEnvironmentVariable("SCADABRIDGE_FORMAT");
        if (!string.IsNullOrEmpty(envFormat))
            config.DefaultFormat = envFormat;

        // Credentials from environment variables only (never the config file).
        var envUsername = Environment.GetEnvironmentVariable("SCADABRIDGE_USERNAME");
        if (!string.IsNullOrEmpty(envUsername))
            config.Username = envUsername;

        var envPassword = Environment.GetEnvironmentVariable("SCADABRIDGE_PASSWORD");
        if (!string.IsNullOrEmpty(envPassword))
            config.Password = envPassword;

        return config;
    }

    private class CliConfigFile
    {
        /// <summary>Management API URL from the config file.</summary>
        public string? ManagementUrl { get; set; }
        /// <summary>Default output format from the config file.</summary>
        public string? DefaultFormat { get; set; }
    }
}
