use serde::{Deserialize, Serialize};

/// Default values for provctl operations, loaded from configuration.
///
/// This struct ensures that NO magic numbers exist in the codebase.
/// All defaults come from configuration files, following the
/// M-DOCUMENTED-MAGIC guideline.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Defaults {
    /// Default timeout for process spawn operations (seconds)
    pub spawn_timeout_secs: u64,

    /// Default timeout for health checks (seconds)
    pub health_check_timeout_secs: u64,

    /// Default interval between health checks (seconds)
    pub health_check_interval_secs: u64,

    /// Default maximum failed health checks before marking unhealthy
    pub health_check_max_failures: u32,

    /// Default interval to wait before restarting a failed service (seconds)
    pub restart_delay_secs: u64,

    /// Default maximum number of restart attempts
    pub max_restart_attempts: u32,

    /// Default path for PID files (uses placeholders like {service_name})
    pub pid_file_path: String,

    /// Default path for log files (uses placeholders like {service_name})
    pub log_file_path: String,

    /// Default maximum log file size before rotation (bytes)
    pub log_file_max_size_bytes: u64,

    /// Default number of log files to keep during rotation
    pub log_file_retention_count: u32,

    /// Default buffer size for reading log files (bytes)
    pub log_read_buffer_size: usize,

    /// Enable auto-restart by default
    pub auto_restart_enabled: bool,

    /// Default verbosity level (0=quiet, 1=normal, 2=verbose, 3=debug)
    pub verbosity_level: u8,
}

/// Error type for defaults validation.
#[derive(Debug)]
pub struct DefaultsValidationError(pub String);

impl Default for Defaults {
    fn default() -> Self {
        Self {
            spawn_timeout_secs: 30,
            health_check_timeout_secs: 5,
            health_check_interval_secs: 10,
            health_check_max_failures: 3,
            restart_delay_secs: 5,
            max_restart_attempts: 3,
            pid_file_path: "/tmp/{service_name}.pid".to_string(),
            log_file_path: "{home}/.local/share/provctl/logs/{service_name}.log".to_string(),
            log_file_max_size_bytes: 10 * 1024 * 1024, // 10 MB
            log_file_retention_count: 5,
            log_read_buffer_size: 8192,
            auto_restart_enabled: true,
            verbosity_level: 1,
        }
    }
}

impl Defaults {
    /// Expands placeholder variables in paths.
    ///
    /// Supports:
    /// - `{service_name}` - replaced with the service name
    /// - `{home}` - replaced with user's home directory
    /// - `{tmp}` - replaced with system temp directory
    ///
    /// # Examples
    ///
    /// ```ignore
    /// let defaults = Defaults::default();
    /// let path = defaults.expand_path(
    ///     "/var/run/{service_name}.pid",
    ///     "my-service"
    /// );
    /// assert_eq!(path, "/var/run/my-service.pid");
    /// ```
    pub fn expand_path(&self, template: &str, service_name: &str) -> String {
        let mut result = template.to_string();

        result = result.replace("{service_name}", service_name);

        if let Ok(home) = std::env::var("HOME") {
            result = result.replace("{home}", &home);
        }

        result = result.replace("{tmp}", &std::env::temp_dir().to_string_lossy());

        result
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_defaults_construction() {
        let defaults = Defaults::default();
        assert_eq!(defaults.spawn_timeout_secs, 30);
        assert_eq!(defaults.health_check_timeout_secs, 5);
        assert_eq!(defaults.auto_restart_enabled, true);
    }

    #[test]
    fn test_path_expansion_service_name() {
        let defaults = Defaults::default();
        let expanded = defaults.expand_path("/tmp/{service_name}.pid", "api");
        assert_eq!(expanded, "/tmp/api.pid");
    }

    #[test]
    fn test_path_expansion_multiple_placeholders() {
        let defaults = Defaults::default();
        let expanded = defaults.expand_path("/var/run/{service_name}/{service_name}.pid", "web");
        assert_eq!(expanded, "/var/run/web/web.pid");
    }

    #[test]
    fn test_log_file_size_is_reasonable() {
        let defaults = Defaults::default();
        // 10 MB is reasonable default for log rotation
        assert!(defaults.log_file_max_size_bytes > 1024 * 1024);
        assert!(defaults.log_file_max_size_bytes < 1024 * 1024 * 1024);
    }
}
