/// Environment detection — which deployment context are we in?

/// The current deployment environment.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Environment {
    /// Local developer machine. Verbose errors, hot reload, relaxed auth.
    Development,
    /// Pre-production environment. Production build, test data.
    Staging,
    /// Live production. Minimal logging, strict auth, performance mode.
    Production,
}

impl Environment {
    /// Detect from the `EL_ENV` environment variable (or `APP_ENV`, `RUST_ENV`).
    ///
    /// Falls back to Development if unset or unrecognized.
    pub fn current() -> Self {
        let val = std::env::var("EL_ENV")
            .or_else(|_| std::env::var("APP_ENV"))
            .or_else(|_| std::env::var("RUST_ENV"))
            .unwrap_or_default();

        Self::from_str(&val)
    }

    /// Parse from a string.
    pub fn from_str(s: &str) -> Self {
        match s.to_lowercase().as_str() {
            "production" | "prod" => Environment::Production,
            "staging" | "stage" => Environment::Staging,
            _ => Environment::Development,
        }
    }

    /// The canonical name for this environment.
    pub fn name(&self) -> &'static str {
        match self {
            Environment::Development => "development",
            Environment::Staging => "staging",
            Environment::Production => "production",
        }
    }

    /// Whether this is a production environment.
    pub fn is_production(&self) -> bool {
        matches!(self, Environment::Production)
    }

    /// Whether this is a development environment.
    pub fn is_development(&self) -> bool {
        matches!(self, Environment::Development)
    }

    /// Whether debug features should be enabled.
    pub fn debug_enabled(&self) -> bool {
        !self.is_production()
    }
}

impl std::fmt::Display for Environment {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.name())
    }
}

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

    #[test]
    fn parse_production() {
        assert_eq!(Environment::from_str("production"), Environment::Production);
        assert_eq!(Environment::from_str("prod"), Environment::Production);
        assert_eq!(Environment::from_str("PRODUCTION"), Environment::Production);
    }

    #[test]
    fn parse_staging() {
        assert_eq!(Environment::from_str("staging"), Environment::Staging);
        assert_eq!(Environment::from_str("stage"), Environment::Staging);
    }

    #[test]
    fn parse_development_fallback() {
        assert_eq!(Environment::from_str("dev"), Environment::Development);
        assert_eq!(Environment::from_str(""), Environment::Development);
        assert_eq!(Environment::from_str("unknown"), Environment::Development);
    }

    #[test]
    fn production_is_production() {
        assert!(Environment::Production.is_production());
        assert!(!Environment::Development.is_production());
    }

    #[test]
    fn development_debug_enabled() {
        assert!(Environment::Development.debug_enabled());
        assert!(!Environment::Production.debug_enabled());
    }

    #[test]
    fn environment_name() {
        assert_eq!(Environment::Production.name(), "production");
        assert_eq!(Environment::Staging.name(), "staging");
        assert_eq!(Environment::Development.name(), "development");
    }

    #[test]
    fn display() {
        assert_eq!(format!("{}", Environment::Production), "production");
    }
}
