use crate::utils;
use serde::{Deserialize, Serialize};
use std::env;
use std::fs;
use std::path::{Path, PathBuf};

#[cfg(feature = "crypto")]
pub mod encryption;
pub mod features;
#[cfg(feature = "crypto")]
pub use encryption::ConfigEncryption;
pub use features::FeatureConfig;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
    pub server: ServerConfig,
    pub database: DatabaseConfig,
    pub session: SessionConfig,
    pub cors: CorsConfig,
    #[serde(rename = "static")]
    pub static_files: StaticConfig,
    pub server_dirs: ServerDirConfig,
    pub security: SecurityConfig,
    pub oauth: OAuthConfig,
    pub email: EmailConfig,
    pub redis: RedisConfig,
    pub app: AppConfig,
    pub logging: LoggingConfig,
    #[cfg(feature = "content-db")]
    pub content: ContentConfig,
    pub features: FeatureConfig,
    #[serde(default = "default_root_path")]
    pub root_path: String,

    // Encryption instance (not serialized)
    #[serde(skip)]
    #[cfg(feature = "crypto")]
    pub encryption: Option<ConfigEncryption>,
}

fn default_root_path() -> String {
    // Initialize utils if not already done
    utils::init();

    // Use the utils project root detection
    utils::get_project_root().to_string_lossy().to_string()
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerConfig {
    pub protocol: Protocol,
    pub host: String,
    pub port: u16,
    pub environment: Environment,
    pub log_level: String,
    pub tls: Option<TlsConfig>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DatabaseConfig {
    pub url: String,
    pub max_connections: u32,
    pub min_connections: u32,
    pub connect_timeout: u64,
    pub idle_timeout: u64,
    pub max_lifetime: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SessionConfig {
    pub secret: String,
    pub cookie_name: String,
    pub cookie_secure: bool,
    pub cookie_http_only: bool,
    pub cookie_same_site: String,
    pub max_age: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CorsConfig {
    pub allowed_origins: Vec<String>,
    pub allowed_methods: Vec<String>,
    pub allowed_headers: Vec<String>,
    pub allow_credentials: bool,
    pub max_age: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StaticConfig {
    pub assets_dir: String,
    pub site_root: String,
    pub site_pkg_dir: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerDirConfig {
    pub public_dir: String,
    pub uploads_dir: String,
    pub logs_dir: String,
    pub temp_dir: String,
    pub cache_dir: String,
    pub config_dir: String,
    pub data_dir: String,
    pub backup_dir: String,
    pub template_dir: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityConfig {
    pub enable_csrf: bool,
    pub csrf_token_name: String,
    pub rate_limit_requests: u32,
    pub rate_limit_window: u64,
    pub bcrypt_cost: u32,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OAuthConfig {
    pub enabled: bool,
    pub google: Option<OAuthProvider>,
    pub github: Option<OAuthProvider>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OAuthProvider {
    pub client_id: String,
    pub client_secret: String,
    pub redirect_uri: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EmailConfig {
    pub enabled: bool,
    pub provider: String,
    pub smtp_host: String,
    pub smtp_port: u16,
    pub smtp_username: String,
    pub smtp_password: String,
    pub smtp_use_tls: bool,
    pub smtp_use_starttls: bool,
    pub sendgrid_api_key: String,
    pub sendgrid_endpoint: String,
    pub from_email: String,
    pub from_name: String,
    pub template_dir: Option<String>,
    pub email_enabled: Option<bool>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RedisConfig {
    pub enabled: bool,
    pub url: String,
    pub pool_size: u32,
    pub connection_timeout: u64,
    pub command_timeout: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppConfig {
    pub name: String,
    pub version: String,
    pub debug: bool,
    pub enable_metrics: bool,
    pub enable_health_check: bool,
    pub enable_compression: bool,
    pub max_request_size: u64,
    pub admin_email: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LoggingConfig {
    pub format: String,
    pub level: String,
    pub file_path: String,
    pub max_file_size: u64,
    pub max_files: u32,
    pub enable_console: bool,
    pub enable_file: bool,
}

#[cfg(feature = "content-db")]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContentConfig {
    pub enabled: bool,
    pub content_dir: String,
    pub cache_enabled: bool,
    pub cache_ttl: u64,
    pub max_file_size: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TlsConfig {
    pub cert_path: PathBuf,
    pub key_path: PathBuf,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum Protocol {
    Http,
    Https,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum Environment {
    Development,
    Production,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ServerDirType {
    Public,
    Uploads,
    Logs,
    Temp,
    Cache,
    Config,
    Data,
    Backup,
}

#[derive(Debug)]
pub enum ConfigError {
    ReadError(String),
    ParseError(String),
    ValidationError(String),
    #[allow(dead_code)]
    InvalidPort(u16),
    MissingFile(String),
    #[allow(dead_code)]
    DirectoryCreationError(String),
    #[allow(dead_code)]
    MissingTlsCert(String),
    #[allow(dead_code)]
    EncryptionError(String),
}

impl std::fmt::Display for ConfigError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            ConfigError::ReadError(msg) => write!(f, "Read error: {}", msg),
            ConfigError::ParseError(msg) => write!(f, "Parse error: {}", msg),
            ConfigError::ValidationError(msg) => write!(f, "Validation error: {}", msg),
            ConfigError::InvalidPort(port) => write!(f, "Invalid port number: {}", port),
            ConfigError::MissingFile(file) => write!(f, "Missing file: {}", file),
            ConfigError::DirectoryCreationError(msg) => {
                write!(f, "Directory creation error: {}", msg)
            }
            ConfigError::MissingTlsCert(msg) => write!(f, "Missing TLS certificate: {}", msg),
            ConfigError::EncryptionError(msg) => write!(f, "Encryption error: {}", msg),
        }
    }
}

impl std::error::Error for ConfigError {}

impl Config {
    /// Load configuration from TOML file with environment variable overrides
    pub fn load() -> Result<Self, ConfigError> {
        // Initialize path utilities first
        utils::init();

        // Load .env file if it exists
        dotenvy::dotenv().ok();

        // Try to determine configuration file path
        let mut config = match Self::determine_config_file() {
            Ok(config_file) => {
                // Load and parse TOML file
                Self::load_from_file(&config_file)?
            }
            Err(_) => {
                // No config file found, create default and optionally save it
                let default_config = Self::create_default_config_for_environment()?;

                // Try to save default config if enabled
                let auto_create = std::env::var("AUTO_CREATE_CONFIG")
                    .unwrap_or_else(|_| "true".to_string())
                    .to_lowercase();

                if auto_create == "true" || auto_create == "1" {
                    if let Ok(env) = std::env::var("ENVIRONMENT") {
                        if env.to_lowercase() == "development" || env.to_lowercase() == "dev" {
                            if let Err(e) = Self::save_default_config(&default_config) {
                                eprintln!("Warning: Could not save default config: {}", e);
                            }
                        }
                    }
                }
                default_config
            }
        };

        // Initialize encryption system
        #[cfg(feature = "crypto")]
        {
            config.encryption = Some(ConfigEncryption::new(&config.root_path).map_err(|e| {
                ConfigError::EncryptionError(format!("Failed to initialize encryption: {}", e))
            })?);
        }

        // Apply environment variable overrides
        config = Self::apply_env_overrides(config)?;

        // Substitute environment variables in string values
        config = Self::substitute_env_vars(config)?;

        // Decrypt encrypted values
        config = Self::decrypt_encrypted_values(config)?;

        // Resolve relative paths to absolute paths
        config = Self::resolve_paths(config)?;

        // Validate configuration
        config.validate()?;

        Ok(config)
    }

    /// Resolve relative paths to absolute paths using ROOT_PATH
    fn resolve_paths(mut config: Self) -> Result<Self, ConfigError> {
        let root_path = PathBuf::from(&config.root_path);

        // Resolve static file paths
        config.static_files.assets_dir =
            Self::resolve_path(&root_path, &config.static_files.assets_dir)?;
        config.static_files.site_root =
            Self::resolve_path(&root_path, &config.static_files.site_root)?;
        config.static_files.site_pkg_dir =
            Self::resolve_path(&root_path, &config.static_files.site_pkg_dir)?;

        // Resolve server directory paths
        config.server_dirs.public_dir =
            Self::resolve_path(&root_path, &config.server_dirs.public_dir)?;
        config.server_dirs.uploads_dir =
            Self::resolve_path(&root_path, &config.server_dirs.uploads_dir)?;
        config.server_dirs.logs_dir = Self::resolve_path(&root_path, &config.server_dirs.logs_dir)?;
        config.server_dirs.temp_dir = Self::resolve_path(&root_path, &config.server_dirs.temp_dir)?;
        config.server_dirs.cache_dir =
            Self::resolve_path(&root_path, &config.server_dirs.cache_dir)?;
        config.server_dirs.config_dir =
            Self::resolve_path(&root_path, &config.server_dirs.config_dir)?;
        config.server_dirs.data_dir = Self::resolve_path(&root_path, &config.server_dirs.data_dir)?;
        config.server_dirs.backup_dir =
            Self::resolve_path(&root_path, &config.server_dirs.backup_dir)?;

        // Resolve TLS certificate paths if present
        if let Some(ref mut tls) = config.server.tls {
            tls.cert_path = PathBuf::from(Self::resolve_path(
                &root_path,
                &tls.cert_path.to_string_lossy(),
            )?);
            tls.key_path = PathBuf::from(Self::resolve_path(
                &root_path,
                &tls.key_path.to_string_lossy(),
            )?);
        }

        // Resolve logging file path
        config.logging.file_path = Self::resolve_path(&root_path, &config.logging.file_path)?;

        // Resolve content directory path if content feature is enabled
        #[cfg(feature = "content-db")]
        {
            config.content.content_dir =
                Self::resolve_path(&root_path, &config.content.content_dir)?;
        }

        Ok(config)
    }

    /// Resolve a relative path to an absolute path using the root path
    fn resolve_path(root_path: &PathBuf, path: &str) -> Result<String, ConfigError> {
        let path_buf = PathBuf::from(path);

        // If the path is already absolute, return it as-is
        if path_buf.is_absolute() {
            return Ok(path.to_string());
        }

        // Resolve relative path against root path
        let resolved = root_path.join(path_buf);
        let canonical = resolved.canonicalize().unwrap_or(resolved);

        Ok(canonical.to_string_lossy().to_string())
    }

    /// Get the absolute path for a given relative path
    #[allow(dead_code)]
    pub fn get_absolute_path(&self, relative_path: &str) -> Result<String, ConfigError> {
        let root_path = PathBuf::from(&self.root_path);
        Self::resolve_path(&root_path, relative_path)
    }

    /// Determine which configuration file to use
    fn determine_config_file() -> Result<PathBuf, ConfigError> {
        // Check for explicit config file path
        if let Ok(config_path) = env::var("CONFIG_FILE") {
            return Ok(PathBuf::from(config_path));
        }

        // Check for environment-specific config
        let env = env::var("ENVIRONMENT").unwrap_or_else(|_| "development".to_string());
        let env_config = match env.to_lowercase().as_str() {
            "production" | "prod" => "config.prod.toml",
            "development" | "dev" => "config.dev.toml",
            _ => "config.toml",
        };

        // Look for config file in current directory first, then in parent directories
        let mut current_dir = env::current_dir().map_err(|e| {
            ConfigError::ReadError(format!("Failed to get current directory: {}", e))
        })?;

        loop {
            let config_path = current_dir.join(env_config);
            if config_path.exists() {
                return Ok(config_path);
            }

            // Try the default config.toml if environment-specific doesn't exist
            if env_config != "config.toml" {
                let default_path = current_dir.join("config.toml");
                if default_path.exists() {
                    return Ok(default_path);
                }
            }

            // Move up one directory
            if let Some(parent) = current_dir.parent() {
                current_dir = parent.to_path_buf();
            } else {
                break;
            }
        }

        Err(ConfigError::MissingFile(format!(
            "Configuration file '{}' not found. Will use default configuration.",
            env_config
        )))
    }

    /// Load configuration from a specific file
    pub fn load_from_file(path: &PathBuf) -> Result<Self, ConfigError> {
        let contents = fs::read_to_string(path).map_err(|e| {
            ConfigError::ReadError(format!("Failed to read {}: {}", path.display(), e))
        })?;

        toml::from_str(&contents)
            .map_err(|e| ConfigError::ParseError(format!("Failed to parse TOML: {}", e)))
    }

    /// Apply environment variable overrides to configuration
    fn apply_env_overrides(mut config: Self) -> Result<Self, ConfigError> {
        // Server overrides
        if let Ok(protocol) = env::var("SERVER_PROTOCOL") {
            config.server.protocol = match protocol.to_lowercase().as_str() {
                "https" => Protocol::Https,
                _ => Protocol::Http,
            };
        }
        if let Ok(host) = env::var("SERVER_HOST") {
            config.server.host = host;
        }
        if let Ok(port) = env::var("SERVER_PORT") {
            config.server.port = port
                .parse()
                .map_err(|_| ConfigError::ParseError(format!("Invalid port number: {}", port)))?;
        }
        if let Ok(env) = env::var("ENVIRONMENT") {
            config.server.environment = match env.to_lowercase().as_str() {
                "production" | "prod" => Environment::Production,
                _ => Environment::Development,
            };
        }
        if let Ok(log_level) = env::var("LOG_LEVEL") {
            config.server.log_level = log_level;
        }

        // TLS overrides
        if let Ok(cert_path) = env::var("TLS_CERT_PATH") {
            if let Ok(key_path) = env::var("TLS_KEY_PATH") {
                config.server.tls = Some(TlsConfig {
                    cert_path: PathBuf::from(cert_path),
                    key_path: PathBuf::from(key_path),
                });
            }
        }

        // Database overrides
        if let Ok(database_url) = env::var("DATABASE_URL") {
            config.database.url = database_url;
        }

        // Session overrides
        if let Ok(session_secret) = env::var("SESSION_SECRET") {
            config.session.secret = session_secret;
        }

        // Root path override
        if let Ok(root_path) = env::var("ROOT_PATH") {
            config.root_path = root_path;
        }

        Ok(config)
    }

    /// Substitute environment variables in string values
    fn substitute_env_vars(mut config: Self) -> Result<Self, ConfigError> {
        // Database URL substitution
        config.database.url = Self::substitute_env_in_string(&config.database.url);

        // Session secret substitution
        config.session.secret = Self::substitute_env_in_string(&config.session.secret);

        // Email configuration substitution
        config.email.smtp_username = Self::substitute_env_in_string(&config.email.smtp_username);
        config.email.smtp_password = Self::substitute_env_in_string(&config.email.smtp_password);
        config.email.sendgrid_api_key =
            Self::substitute_env_in_string(&config.email.sendgrid_api_key);

        // OAuth configuration substitution
        if let Some(ref mut google) = config.oauth.google {
            google.client_id = Self::substitute_env_in_string(&google.client_id);
            google.client_secret = Self::substitute_env_in_string(&google.client_secret);
        }
        if let Some(ref mut github) = config.oauth.github {
            github.client_id = Self::substitute_env_in_string(&github.client_id);
            github.client_secret = Self::substitute_env_in_string(&github.client_secret);
        }

        // Redis URL substitution
        config.redis.url = Self::substitute_env_in_string(&config.redis.url);

        Ok(config)
    }

    /// Substitute environment variables in a string
    pub fn substitute_env_in_string(input: &str) -> String {
        let mut result = input.to_string();

        // Match patterns like ${VAR_NAME} or $VAR_NAME
        let re = regex::Regex::new(r"\$\{([^}]+)\}|\$([A-Za-z_][A-Za-z0-9_]*)").unwrap();

        result = re
            .replace_all(&result, |caps: &regex::Captures| {
                let var_name = caps.get(1).or_else(|| caps.get(2)).unwrap().as_str();
                env::var(var_name).unwrap_or_else(|_| caps.get(0).unwrap().as_str().to_string())
            })
            .to_string();

        result
    }

    /// Decrypt encrypted configuration values (values starting with '@')
    fn decrypt_encrypted_values(config: Self) -> Result<Self, ConfigError> {
        #[cfg(feature = "crypto")]
        if let Some(ref encryption) = config.encryption {
            // Decrypt database configuration
            config.database.url = encryption
                .decrypt_if_encrypted(&config.database.url)
                .map_err(|e| {
                    ConfigError::EncryptionError(format!("Failed to decrypt database.url: {}", e))
                })?;

            // Decrypt session configuration
            config.session.secret = encryption
                .decrypt_if_encrypted(&config.session.secret)
                .map_err(|e| {
                    ConfigError::EncryptionError(format!("Failed to decrypt session.secret: {}", e))
                })?;

            // Decrypt email configuration
            config.email.smtp_username = encryption
                .decrypt_if_encrypted(&config.email.smtp_username)
                .map_err(|e| {
                    ConfigError::EncryptionError(format!(
                        "Failed to decrypt email.smtp_username: {}",
                        e
                    ))
                })?;
            config.email.smtp_password = encryption
                .decrypt_if_encrypted(&config.email.smtp_password)
                .map_err(|e| {
                    ConfigError::EncryptionError(format!(
                        "Failed to decrypt email.smtp_password: {}",
                        e
                    ))
                })?;
            config.email.sendgrid_api_key = encryption
                .decrypt_if_encrypted(&config.email.sendgrid_api_key)
                .map_err(|e| {
                    ConfigError::EncryptionError(format!(
                        "Failed to decrypt email.sendgrid_api_key: {}",
                        e
                    ))
                })?;

            // Decrypt OAuth configuration
            if let Some(ref mut google) = config.oauth.google {
                google.client_id =
                    encryption
                        .decrypt_if_encrypted(&google.client_id)
                        .map_err(|e| {
                            ConfigError::EncryptionError(format!(
                                "Failed to decrypt oauth.google.client_id: {}",
                                e
                            ))
                        })?;
                google.client_secret = encryption
                    .decrypt_if_encrypted(&google.client_secret)
                    .map_err(|e| {
                        ConfigError::EncryptionError(format!(
                            "Failed to decrypt oauth.google.client_secret: {}",
                            e
                        ))
                    })?;
            }
            if let Some(ref mut github) = config.oauth.github {
                github.client_id =
                    encryption
                        .decrypt_if_encrypted(&github.client_id)
                        .map_err(|e| {
                            ConfigError::EncryptionError(format!(
                                "Failed to decrypt oauth.github.client_id: {}",
                                e
                            ))
                        })?;
                github.client_secret = encryption
                    .decrypt_if_encrypted(&github.client_secret)
                    .map_err(|e| {
                        ConfigError::EncryptionError(format!(
                            "Failed to decrypt oauth.github.client_secret: {}",
                            e
                        ))
                    })?;
            }

            // Decrypt Redis configuration
            config.redis.url = encryption
                .decrypt_if_encrypted(&config.redis.url)
                .map_err(|e| {
                    ConfigError::EncryptionError(format!("Failed to decrypt redis.url: {}", e))
                })?;
        }

        Ok(config)
    }

    /// Encrypt a configuration value
    #[allow(dead_code)]
    #[cfg(feature = "crypto")]
    pub fn encrypt_value(&self, value: &str) -> Result<String, ConfigError> {
        if let Some(ref encryption) = self.encryption {
            encryption.encrypt(value).map_err(|e| {
                ConfigError::EncryptionError(format!("Failed to encrypt value: {}", e))
            })
        } else {
            Err(ConfigError::EncryptionError(
                "Encryption not initialized".to_string(),
            ))
        }
    }

    /// Decrypt a configuration value
    #[allow(dead_code)]
    #[cfg(feature = "crypto")]
    pub fn decrypt_value(&self, value: &str) -> Result<String, ConfigError> {
        if let Some(ref encryption) = self.encryption {
            encryption.decrypt_if_encrypted(value).map_err(|e| {
                ConfigError::EncryptionError(format!("Failed to decrypt value: {}", e))
            })
        } else {
            Err(ConfigError::EncryptionError(
                "Encryption not initialized".to_string(),
            ))
        }
    }

    /// Check if a value is encrypted
    #[allow(dead_code)]
    #[cfg(feature = "crypto")]
    pub fn is_encrypted(value: &str) -> bool {
        ConfigEncryption::is_encrypted(value)
    }

    /// Get the encryption key file path
    #[allow(dead_code)]
    #[cfg(feature = "crypto")]
    pub fn encryption_key_path(&self) -> Option<&PathBuf> {
        self.encryption.as_ref().map(|e| e.key_file_path())
    }

    /// Verify the encryption key
    #[allow(dead_code)]
    #[cfg(feature = "crypto")]
    pub fn verify_encryption_key(&self) -> Result<(), ConfigError> {
        if let Some(ref encryption) = self.encryption {
            encryption.verify_key().map_err(|e| {
                ConfigError::EncryptionError(format!("Key verification failed: {}", e))
            })
        } else {
            Err(ConfigError::EncryptionError(
                "Encryption not initialized".to_string(),
            ))
        }
    }

    /// Validate the configuration
    pub fn validate(&self) -> Result<(), ConfigError> {
        // Validate port range
        if self.server.port == 0 {
            return Err(ConfigError::ValidationError(
                "Server port must be between 1 and 65535".to_string(),
            ));
        }

        // Validate HTTPS configuration
        if self.server.protocol == Protocol::Https && self.server.tls.is_none() {
            return Err(ConfigError::ValidationError(
                "HTTPS protocol requires TLS configuration".to_string(),
            ));
        }

        // Validate database connection string only if database features are enabled
        let database_features_enabled = self.features.auth.enabled || self.features.content.enabled;
        if database_features_enabled && self.database.url.is_empty() {
            return Err(ConfigError::ValidationError(
                "Database URL cannot be empty when database features are enabled".to_string(),
            ));
        }

        // Validate session secret
        if self.session.secret.is_empty() {
            return Err(ConfigError::ValidationError(
                "Session secret cannot be empty".to_string(),
            ));
        }

        // Validate root path exists
        let root_path = Path::new(&self.root_path);
        if !root_path.exists() {
            return Err(ConfigError::ValidationError(format!(
                "Root path '{}' does not exist",
                self.root_path
            )));
        }

        Ok(())
    }

    /// Create server directories if they don't exist
    #[allow(dead_code)]
    pub fn create_server_directories(&self) -> Result<(), ConfigError> {
        let directories = [
            &self.server_dirs.public_dir,
            &self.server_dirs.uploads_dir,
            &self.server_dirs.logs_dir,
            &self.server_dirs.temp_dir,
            &self.server_dirs.cache_dir,
            &self.server_dirs.config_dir,
            &self.server_dirs.data_dir,
            &self.server_dirs.backup_dir,
        ];

        for dir in directories {
            self.create_directory(dir)?;
        }

        Ok(())
    }

    /// Create a directory if it doesn't exist
    #[allow(dead_code)]
    pub fn create_directory(&self, path: &str) -> Result<(), ConfigError> {
        let path = Path::new(path);
        if !path.exists() {
            fs::create_dir_all(path).map_err(|e| {
                ConfigError::DirectoryCreationError(format!(
                    "Failed to create directory '{}': {}",
                    path.display(),
                    e
                ))
            })?;
        }
        Ok(())
    }

    /// Get the path for a specific server directory type
    #[allow(dead_code)]
    pub fn get_server_dir_path(&self, dir_type: ServerDirType) -> &str {
        match dir_type {
            ServerDirType::Public => &self.server_dirs.public_dir,
            ServerDirType::Uploads => &self.server_dirs.uploads_dir,
            ServerDirType::Logs => &self.server_dirs.logs_dir,
            ServerDirType::Temp => &self.server_dirs.temp_dir,
            ServerDirType::Cache => &self.server_dirs.cache_dir,
            ServerDirType::Config => &self.server_dirs.config_dir,
            ServerDirType::Data => &self.server_dirs.data_dir,
            ServerDirType::Backup => &self.server_dirs.backup_dir,
        }
    }

    /// Validate that all required directories exist
    #[allow(dead_code)]
    pub fn validate_directories(&self) -> Result<(), ConfigError> {
        let directories = [
            (&self.server_dirs.public_dir, "public"),
            (&self.server_dirs.uploads_dir, "uploads"),
            (&self.server_dirs.logs_dir, "logs"),
            (&self.server_dirs.temp_dir, "temp"),
            (&self.server_dirs.cache_dir, "cache"),
            (&self.server_dirs.config_dir, "config"),
            (&self.server_dirs.data_dir, "data"),
            (&self.server_dirs.backup_dir, "backup"),
        ];

        for (path, name) in &directories {
            let path_obj = Path::new(path);
            if !path_obj.exists() {
                return Err(ConfigError::ValidationError(format!(
                    "{} directory '{}' does not exist",
                    name, path
                )));
            }
            if !path_obj.is_dir() {
                return Err(ConfigError::ValidationError(format!(
                    "{} path '{}' exists but is not a directory",
                    name, path
                )));
            }
        }

        Ok(())
    }

    /// Get server address for binding
    pub fn server_address(&self) -> String {
        format!("{}:{}", self.server.host, self.server.port)
    }

    /// Get full server URL
    #[allow(dead_code)]
    pub fn server_url(&self) -> String {
        match self.server.protocol {
            Protocol::Http => format!("http://{}:{}", self.server.host, self.server.port),
            Protocol::Https => format!("https://{}:{}", self.server.host, self.server.port),
        }
    }

    /// Check if running in development mode
    #[allow(dead_code)]
    pub fn is_development(&self) -> bool {
        matches!(self.server.environment, Environment::Development)
    }

    /// Check if running in production mode
    pub fn is_production(&self) -> bool {
        matches!(self.server.environment, Environment::Production)
    }

    /// Check if TLS is required
    #[allow(dead_code)]
    pub fn requires_tls(&self) -> bool {
        matches!(self.server.protocol, Protocol::Https)
    }

    /// Get database pool configuration
    #[allow(dead_code)]
    pub fn database_pool_config(&self) -> DatabasePoolConfig {
        DatabasePoolConfig {
            url: self.database.url.clone(),
            max_connections: self.database.max_connections,
            min_connections: self.database.min_connections,
            connect_timeout: std::time::Duration::from_secs(self.database.connect_timeout),
            idle_timeout: std::time::Duration::from_secs(self.database.idle_timeout),
            max_lifetime: std::time::Duration::from_secs(self.database.max_lifetime),
        }
    }

    /// Create a default configuration for the current environment
    fn create_default_config_for_environment() -> Result<Self, ConfigError> {
        let env = std::env::var("ENVIRONMENT").unwrap_or_else(|_| "development".to_string());

        let mut config = Self::default();

        // Adjust config based on environment
        match env.to_lowercase().as_str() {
            "production" | "prod" => {
                config.server.environment = Environment::Production;
                config.server.log_level = "info".to_string();
                config.app.debug = false;
                config.security.enable_csrf = true;
                config.session.cookie_secure = true;
                config.logging.level = "info".to_string();
                config.logging.format = "json".to_string();
            }
            "development" | "dev" | _ => {
                config.server.environment = Environment::Development;
                config.server.log_level = "debug".to_string();
                config.app.debug = true;
                config.security.enable_csrf = false;
                config.session.cookie_secure = false;
                config.logging.level = "debug".to_string();
                config.logging.format = "pretty".to_string();

                // Default to SQLite for easy development setup
                // Change to PostgreSQL if you need full auth features:
                // "postgresql://postgres:password@localhost:5432/rustelo_dev"
                config.database.url = "sqlite:data/development.db".to_string();
            }
        }

        let auto_create = std::env::var("AUTO_CREATE_CONFIG")
            .unwrap_or_else(|_| "true".to_string())
            .to_lowercase();

        if auto_create == "true" || auto_create == "1" {
            eprintln!("Using default configuration for {} environment", env);
        } else {
            eprintln!(
                "Using default configuration for {} environment (config file creation disabled)",
                env
            );
        }
        Ok(config)
    }

    /// Save default configuration to file
    fn save_default_config(config: &Self) -> Result<(), ConfigError> {
        let env = std::env::var("ENVIRONMENT").unwrap_or_else(|_| "development".to_string());
        let filename = match env.to_lowercase().as_str() {
            "production" | "prod" => "config.prod.toml",
            "development" | "dev" => "config.dev.toml",
            _ => "config.toml",
        };

        let toml_content = toml::to_string_pretty(config)
            .map_err(|e| ConfigError::ParseError(format!("Failed to serialize config: {}", e)))?;

        std::fs::write(filename, toml_content)
            .map_err(|e| ConfigError::ReadError(format!("Failed to write config file: {}", e)))?;

        eprintln!(
            "Created default configuration file: {} (set AUTO_CREATE_CONFIG=false to disable)",
            filename
        );
        Ok(())
    }
}

/// Database pool configuration helper
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub struct DatabasePoolConfig {
    pub url: String,
    pub max_connections: u32,
    pub min_connections: u32,
    pub connect_timeout: std::time::Duration,
    pub idle_timeout: std::time::Duration,
    pub max_lifetime: std::time::Duration,
}

impl Default for Config {
    fn default() -> Self {
        Self {
            server: ServerConfig {
                protocol: Protocol::Http,
                host: "0.0.0.0".to_string(),
                port: 3030,
                environment: Environment::Development,
                log_level: "info".to_string(),
                tls: None,
            },
            database: DatabaseConfig {
                url: "postgresql://username:password@localhost:5432/database_name".to_string(),
                max_connections: 10,
                min_connections: 1,
                connect_timeout: 30,
                idle_timeout: 600,
                max_lifetime: 1800,
            },
            session: SessionConfig {
                secret: "change-this-in-production-to-a-secure-random-string".to_string(),
                cookie_name: "session_id".to_string(),
                cookie_secure: false,
                cookie_http_only: true,
                cookie_same_site: "lax".to_string(),
                max_age: 3600,
            },
            cors: CorsConfig {
                allowed_origins: vec![
                    "http://localhost:3030".to_string(),
                    "http://127.0.0.1:3030".to_string(),
                ],
                allowed_methods: vec![
                    "GET".to_string(),
                    "POST".to_string(),
                    "PUT".to_string(),
                    "DELETE".to_string(),
                    "OPTIONS".to_string(),
                ],
                allowed_headers: vec![
                    "Content-Type".to_string(),
                    "Authorization".to_string(),
                    "X-Requested-With".to_string(),
                ],
                allow_credentials: true,
                max_age: 3600,
            },
            static_files: StaticConfig {
                assets_dir: "public".to_string(),
                site_root: "target/site".to_string(),
                site_pkg_dir: "pkg".to_string(),
            },
            server_dirs: ServerDirConfig {
                public_dir: "public".to_string(),
                uploads_dir: "uploads".to_string(),
                logs_dir: "logs".to_string(),
                temp_dir: "tmp".to_string(),
                cache_dir: "cache".to_string(),
                config_dir: "config".to_string(),
                data_dir: "data".to_string(),
                backup_dir: "backups".to_string(),
                template_dir: Some("templates".to_string()),
            },
            security: SecurityConfig {
                enable_csrf: true,
                csrf_token_name: "csrf_token".to_string(),
                rate_limit_requests: 100,
                rate_limit_window: 60,
                bcrypt_cost: 12,
            },
            oauth: OAuthConfig {
                enabled: false,
                google: None,
                github: None,
            },
            email: EmailConfig {
                enabled: false,
                provider: "console".to_string(),
                smtp_host: "smtp.gmail.com".to_string(),
                smtp_port: 587,
                smtp_username: "your-email@gmail.com".to_string(),
                smtp_password: "your-app-password".to_string(),
                smtp_use_tls: false,
                smtp_use_starttls: true,
                sendgrid_api_key: "".to_string(),
                sendgrid_endpoint: "https://api.sendgrid.com/v3/mail/send".to_string(),
                from_email: "noreply@yourapp.com".to_string(),
                from_name: "Your App".to_string(),
                template_dir: None,
                email_enabled: Some(true),
            },
            redis: RedisConfig {
                enabled: false,
                url: "redis://localhost:6379".to_string(),
                pool_size: 10,
                connection_timeout: 5,
                command_timeout: 5,
            },
            app: AppConfig {
                name: "My Rust App".to_string(),
                version: "0.1.0".to_string(),
                debug: true,
                enable_metrics: false,
                enable_health_check: true,
                enable_compression: true,
                max_request_size: 10485760,
                admin_email: Some("admin@example.com".to_string()),
            },
            logging: LoggingConfig {
                format: "json".to_string(),
                level: "info".to_string(),
                file_path: "logs/app.log".to_string(),
                max_file_size: 10485760,
                max_files: 5,
                enable_console: true,
                enable_file: false,
            },
            #[cfg(feature = "content-db")]
            content: ContentConfig {
                enabled: false,
                content_dir: "content".to_string(),
                cache_enabled: true,
                cache_ttl: 3600,
                max_file_size: 5242880,
            },
            features: FeatureConfig::default(),
            #[cfg(feature = "crypto")]
            encryption: None,
            root_path: default_root_path(),
        }
    }
}

// TLS configuration functions
#[cfg(feature = "tls")]
#[allow(dead_code)]
pub async fn create_tls_config(
    cert_path: &PathBuf,
    key_path: &PathBuf,
) -> Result<axum_server::tls_rustls::RustlsConfig, ConfigError> {
    axum_server::tls_rustls::RustlsConfig::from_pem_file(cert_path, key_path)
        .await
        .map_err(|e| ConfigError::ValidationError(format!("Failed to load TLS config: {}", e)))
}

#[cfg(not(feature = "tls"))]
#[allow(dead_code)]
pub async fn create_tls_config(
    _cert_path: &PathBuf,
    _key_path: &PathBuf,
) -> Result<(), ConfigError> {
    Err(ConfigError::ValidationError(
        "TLS support not compiled in".to_string(),
    ))
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fs;
    use tempfile::tempdir;

    #[test]
    fn test_config_loading() {
        let dir = tempdir().unwrap();
        let config_path = dir.path().join("config.toml");

        let config_content = r#"
[server]
protocol = "http"
host = "127.0.0.1"
port = 3030
environment = "development"
log_level = "info"

[database]
url = "postgresql://test:test@localhost:5432/test_db"
max_connections = 10
min_connections = 1
connect_timeout = 30
idle_timeout = 600
max_lifetime = 1800

[session]
secret = "test-secret-key"
cookie_name = "session_id"
cookie_secure = false
cookie_http_only = true
cookie_same_site = "lax"
max_age = 3600

[cors]
allowed_origins = ["http://localhost:3030"]
allowed_methods = ["GET", "POST"]
allowed_headers = ["Content-Type"]
allow_credentials = true
max_age = 3600

[static]
assets_dir = "public"
site_root = "target/site"
site_pkg_dir = "pkg"

[security]
enable_csrf = true
csrf_token_name = "csrf_token"
rate_limit_requests = 100
rate_limit_window = 60
bcrypt_cost = 12

[oauth]
enabled = false

[email]
enabled = false
provider = "console"
smtp_host = "smtp.gmail.com"
smtp_port = 587
smtp_username = "test@example.com"
smtp_password = "password"
smtp_use_tls = true
smtp_use_starttls = false
sendgrid_api_key = ""
sendgrid_endpoint = "https://api.sendgrid.com/v3/mail/send"
from_email = "noreply@example.com"
from_name = "Test App"
template_dir = "templates/email"

[redis]
enabled = false
url = "redis://localhost:6379"
pool_size = 10
connection_timeout = 5
command_timeout = 5

[app]
name = "Test App"
version = "0.1.0"
debug = true
enable_metrics = false
enable_health_check = true
enable_compression = true
max_request_size = 10485760

[logging]
format = "json"
level = "info"
file_path = "logs/app.log"
max_file_size = 10485760
max_files = 5
enable_console = true
enable_file = false

[content]
enabled = false
content_dir = "content"
cache_enabled = true
cache_ttl = 3600
max_file_size = 5242880

[features]
[features.auth]
enabled = true
jwt = true
oauth = false
two_factor = false
sessions = true
password_reset = true
email_verification = true
account_lockout = true

[features.rbac]
enabled = false
database_access = false
file_access = false
content_access = false
api_access = false
categories = false
tags = false
caching = false
audit_logging = false
toml_config = false
hierarchical_permissions = false
dynamic_rules = false

[features.content]
enabled = true
markdown = true
syntax_highlighting = false
file_uploads = false
versioning = false
scheduling = false
seo = false

[features.security]
csrf = true
security_headers = true
rate_limiting = true
input_sanitization = true
sql_injection_protection = true
xss_protection = true
content_security_policy = true

[features.performance]
response_caching = false
query_caching = false
compression = true
connection_pooling = true
lazy_loading = false
background_tasks = false

[features.custom]

[server_dirs]
public_dir = "public"
uploads_dir = "uploads"
logs_dir = "logs"
temp_dir = "tmp"
cache_dir = "cache"
config_dir = "config"
data_dir = "data"
backup_dir = "backups"
"#;

        fs::write(&config_path, config_content).expect("Failed to write config file");

        let config = Config::load_from_file(&config_path).expect("Failed to load config");
        assert_eq!(config.server.host, "127.0.0.1");
        assert_eq!(config.server.port, 3030);
        assert_eq!(config.app.name, "Test App");
    }

    #[test]
    fn test_env_substitution() {
        // Test with a string that has no substitution variables
        let input_no_vars = "postgresql://user:password@localhost:5432/db";
        let result_no_vars = Config::substitute_env_in_string(input_no_vars);
        assert_eq!(
            result_no_vars,
            "postgresql://user:password@localhost:5432/db"
        );

        // Test with PATH environment variable which should exist
        let input_with_path = "Location: ${PATH}";
        let result_with_path = Config::substitute_env_in_string(input_with_path);
        // Should contain "Location: " followed by the PATH value
        assert!(result_with_path.starts_with("Location: "));
        assert!(result_with_path.len() > "Location: ".len());

        // Test with non-existent environment variable
        let input_with_nonexistent = "Value: ${NONEXISTENT_VAR_12345}";
        let result_with_nonexistent = Config::substitute_env_in_string(input_with_nonexistent);
        // Should remain unchanged when variable doesn't exist
        assert_eq!(result_with_nonexistent, "Value: ${NONEXISTENT_VAR_12345}");
    }
}
