using System.Configuration;
using System.Collections.Specialized;

namespace qdr.app.bundleboiler.Configuration
{
    public class AppSettingsHandler
    {
        private readonly string _configPath;
        private readonly System.Configuration.Configuration _configuration;

        #region *** Constructors ***
        /// <summary>
        /// Initializes a new instance of AppSettingsHandler using the default application configuration
        /// </summary>
        public AppSettingsHandler()
            : this(GetDefaultConfigPath())
        {
        }

        /// <summary>
        /// Initializes a new instance of AppSettingsHandler with a specific configuration file path
        /// </summary>
        /// <param name="configPath">Full path to the configuration file</param>
        public AppSettingsHandler(string configPath)
        {
            if (string.IsNullOrEmpty(configPath))
                throw new ArgumentNullException(nameof(configPath));

            if (!File.Exists(configPath))
                throw new FileNotFoundException("Configuration file not found", configPath);

            _configPath = configPath;
            _configuration = ConfigurationManager.OpenExeConfiguration(configPath);
        }
        #endregion

        #region *** Public Read Methods ***

        /// <summary>
        /// Gets a string value from AppSettings
        /// </summary>
        /// <param name="key">The key to look up</param>
        /// <param name="defaultValue">Optional default value if key is not found</param>
        /// <returns>The value from settings or default value</returns>
        public string GetString(string key, string defaultValue = "")
        {
            return ConfigurationManager.AppSettings[key] ?? defaultValue;
        }

        /// <summary>
        /// Gets an integer value from AppSettings
        /// </summary>
        /// <param name="key">The key to look up</param>
        /// <param name="defaultValue">Optional default value if key is not found or parsing fails</param>
        /// <returns>The value from settings or default value</returns>
        public int GetInt(string key, int defaultValue = 0)
        {
            string? value = ConfigurationManager.AppSettings[key];
            return int.TryParse(value, out int result) ? result : defaultValue;
        }

        /// <summary>
        /// Gets a boolean value from AppSettings
        /// </summary>
        /// <param name="key">The key to look up</param>
        /// <param name="defaultValue">Optional default value if key is not found or parsing fails</param>
        /// <returns>The value from settings or default value</returns>
        public bool GetBool(string key, bool defaultValue = false)
        {
            string? value = ConfigurationManager.AppSettings[key];
            return bool.TryParse(value, out bool result) ? result : defaultValue;
        }

        /// <summary>
        /// Gets a DateTime value from AppSettings
        /// </summary>
        /// <param name="key">The key to look up</param>
        /// <param name="defaultValue">Optional default value if key is not found or parsing fails</param>
        /// <returns>The value from settings or default value</returns>
        public DateTime GetDateTime(string key, DateTime? defaultValue = null)
        {
            string? value = ConfigurationManager.AppSettings[key];
            return DateTime.TryParse(value, out DateTime result) ? result : defaultValue ?? DateTime.MinValue;
        }

        /// <summary>
        /// Gets an enum value from AppSettings
        /// </summary>
        /// <typeparam name="T">The enum type</typeparam>
        /// <param name="key">The key to look up</param>
        /// <param name="defaultValue">Optional default value if key is not found or parsing fails</param>
        /// <returns>The value from settings or default value</returns>
        public T GetEnum<T>(string key, T defaultValue) where T : struct
        {
            string? value = ConfigurationManager.AppSettings[key];
            return Enum.TryParse<T>(value, true, out T result) ? result : defaultValue;
        }

        /// <summary>
        /// Checks if a key exists in AppSettings
        /// </summary>
        /// <param name="key">The key to check</param>
        /// <returns>True if the key exists</returns>
        public bool HasKey(string key)
        {
            return ConfigurationManager.AppSettings[key] != null;
        }

        /// <summary>
        /// Gets all settings as a NameValueCollection
        /// </summary>
        /// <returns>NameValueCollection containing all settings</returns>
        public NameValueCollection GetAllSettings()
        {
            return ConfigurationManager.AppSettings;
        }

        #endregion

         #region *** Public Write Methods ***

        /// <summary>
        /// Sets a string value in AppSettings
        /// </summary>
        /// <param name="key">The key to set</param>
        /// <param name="value">The value to store</param>
        public void SetString(string key, string value)
        {
            SetValue(key, value);
        }

        /// <summary>
        /// Sets an integer value in AppSettings
        /// </summary>
        /// <param name="key">The key to set</param>
        /// <param name="value">The value to store</param>
        public void SetInt(string key, int value)
        {
            SetValue(key, value.ToString());
        }

        /// <summary>
        /// Sets a boolean value in AppSettings
        /// </summary>
        /// <param name="key">The key to set</param>
        /// <param name="value">The value to store</param>
        public void SetBool(string key, bool value)
        {
            SetValue(key, value.ToString());
        }

        /// <summary>
        /// Sets a DateTime value in AppSettings
        /// </summary>
        /// <param name="key">The key to set</param>
        /// <param name="value">The value to store</param>
        public void SetDateTime(string key, DateTime value)
        {
            SetValue(key, value.ToString("o")); // ISO 8601 format
        }

        /// <summary>
        /// Sets an enum value in AppSettings
        /// </summary>
        /// <typeparam name="T">The enum type</typeparam>
        /// <param name="key">The key to set</param>
        /// <param name="value">The value to store</param>
        public void SetEnum<T>(string key, T value) where T : struct
        {
            SetValue(key, value.ToString());
        }

        /// <summary>
        /// Removes a setting from AppSettings
        /// </summary>
        /// <param name="key">The key to remove</param>
        public void RemoveSetting(string key)
        {
            if (HasKey(key))
            {
                _configuration.AppSettings.Settings.Remove(key);
                SaveConfiguration();
            }
        }

        /// <summary>
        /// Clear all settings from AppSettings
        /// </summary>
        public void ClearSettings()
        {
            _configuration.AppSettings.Settings.Clear();
            SaveConfiguration();
        }

        #endregion

        #region Private Methods

        private void SetValue(string key, string? value)
        {
            try
            {
                if (HasKey(key))
                {
                    _configuration.AppSettings.Settings[key].Value = value;
                }
                else
                {
                    _configuration.AppSettings.Settings.Add(key, value);
                }
                SaveConfiguration();
            }
            catch (Exception ex)
            {
                throw new ConfigurationErrorsException($"Error setting configuration value for key: {key}", ex);
            }
        }

        private static string GetDefaultConfigPath()
        {
            string exePath = System.Reflection.Assembly.GetExecutingAssembly().Location;
            return exePath + ".config";
        }

        private void SaveConfiguration()
        {
            try
            {
                _configuration.Save(ConfigurationSaveMode.Modified);
                ConfigurationManager.RefreshSection("appSettings");
            }
            catch (Exception ex)
            {
                throw new ConfigurationErrorsException("Error saving configuration changes", ex);
            }
        }

        #endregion
    }
}