use std::env;
use std::fs;
use std::path::PathBuf;

/// Configuration types for SecretumVault integration
use serde::{Deserialize, Serialize};

/// SecretumVault configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecretumVaultConfig {
    /// Server URL for standalone service mode
    /// Example: "http://localhost:8200" for development
    pub server_url: String,

    /// Storage backend selection
    /// Options: "filesystem", "surrealdb", "etcd", "postgresql"
    pub storage_backend: String,

    /// Authentication token for service mode
    /// For embedded mode, leave as None
    pub auth_token: Option<String>,

    /// Vault Transit engine mount point
    /// Default: "transit"
    pub mount_point: String,

    /// Key name within the Transit engine
    /// Default: "provisioning-master"
    pub key_name: String,

    /// Whether to verify TLS certificates
    /// Set to false for development with self-signed certs
    pub tls_verify: bool,

    /// Deployment mode (determined automatically from environment)
    #[serde(default)]
    pub deployment_mode: DeploymentMode,
}

/// Deployment mode for SecretumVault
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum DeploymentMode {
    /// Embedded VaultCore library (development)
    Embedded,
    /// Standalone service (staging/production)
    Service,
}

impl Default for DeploymentMode {
    fn default() -> Self {
        match std::env::var("PROVISIONING_ENV").as_deref() {
            Ok("dev") => DeploymentMode::Embedded,
            _ => DeploymentMode::Service,
        }
    }
}

impl SecretumVaultConfig {
    /// Load configuration from hierarchical sources with mode support
    ///
    /// Priority order:
    /// 1. VAULT_CONFIG environment variable (explicit path)
    /// 2. VAULT_MODE environment variable (mode-specific file)
    /// 3. Default from environment
    ///
    /// After loading, applies environment variable overrides.
    pub fn load_from_hierarchy() -> Result<Self, Box<dyn std::error::Error>> {
        let config = if let Ok(path) = env::var("VAULT_CONFIG") {
            // Explicit config path provided
            let contents = fs::read_to_string(&path)?;
            toml::from_str(&contents)?
        } else if let Ok(mode) = env::var("VAULT_MODE") {
            // Mode-specific config file
            let path = PathBuf::from(format!(
                "provisioning/platform/config/vault-service.{}.toml",
                mode
            ));
            let contents = fs::read_to_string(&path)?;
            toml::from_str(&contents)?
        } else {
            // Fall back to environment-based loading
            Self::from_env()
        };

        Ok(config.apply_env_overrides())
    }

    /// Apply environment variable overrides to configuration
    ///
    /// Overrides take precedence over loaded config values.
    /// Pattern: VAULT_{SECTION}_{KEY}
    fn apply_env_overrides(mut self) -> Self {
        if let Ok(val) = env::var("VAULT_SERVER_URL") {
            self.server_url = val;
        }
        if let Ok(val) = env::var("VAULT_STORAGE_BACKEND") {
            self.storage_backend = val;
        }
        if let Ok(val) = env::var("VAULT_AUTH_TOKEN") {
            self.auth_token = Some(val);
        }
        if let Ok(val) = env::var("VAULT_MOUNT_POINT") {
            self.mount_point = val;
        }
        if let Ok(val) = env::var("VAULT_KEY_NAME") {
            self.key_name = val;
        }
        if let Ok(val) = env::var("VAULT_TLS_VERIFY") {
            self.tls_verify = val.parse().unwrap_or(self.tls_verify);
        }
        self
    }

    /// Create a new SecretumVault configuration from environment and defaults
    pub fn from_env() -> Self {
        let env = std::env::var("PROVISIONING_ENV").unwrap_or_else(|_| "dev".to_string());
        let deployment_mode = DeploymentMode::default();

        Self {
            server_url: std::env::var("SECRETUMVAULT_URL")
                .unwrap_or_else(|_| "http://localhost:8200".to_string()),
            storage_backend: std::env::var("SECRETUMVAULT_STORAGE").unwrap_or_else(|_| {
                match env.as_str() {
                    "dev" => "filesystem".to_string(),
                    "staging" => "surrealdb".to_string(),
                    "prod" | "production" => "etcd".to_string(),
                    _ => "filesystem".to_string(),
                }
            }),
            auth_token: std::env::var("SECRETUMVAULT_TOKEN").ok(),
            mount_point: std::env::var("SECRETUMVAULT_MOUNT_POINT")
                .unwrap_or_else(|_| "transit".to_string()),
            key_name: std::env::var("SECRETUMVAULT_KEY_NAME")
                .unwrap_or_else(|_| "provisioning-master".to_string()),
            tls_verify: !matches!(env.as_str(), "dev" | "development"),
            deployment_mode,
        }
    }

    /// Validate configuration consistency
    pub fn validate(&self) -> Result<(), String> {
        if self.mount_point.is_empty() {
            return Err("mount_point cannot be empty".to_string());
        }

        if self.key_name.is_empty() {
            return Err("key_name cannot be empty".to_string());
        }

        let valid_backends = ["filesystem", "surrealdb", "etcd", "postgresql"];
        if !valid_backends.contains(&self.storage_backend.as_str()) {
            return Err(format!(
                "Invalid storage_backend: {}. Must be one of: {}",
                self.storage_backend,
                valid_backends.join(", ")
            ));
        }

        Ok(())
    }
}

impl Default for SecretumVaultConfig {
    fn default() -> Self {
        Self::from_env()
    }
}

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

    #[test]
    fn test_config_validation_valid() {
        let config = SecretumVaultConfig {
            server_url: "http://localhost:8200".to_string(),
            storage_backend: "filesystem".to_string(),
            auth_token: None,
            mount_point: "transit".to_string(),
            key_name: "test-key".to_string(),
            tls_verify: false,
            deployment_mode: DeploymentMode::Service,
        };

        assert!(config.validate().is_ok());
    }

    #[test]
    fn test_config_validation_invalid_backend() {
        let config = SecretumVaultConfig {
            server_url: "http://localhost:8200".to_string(),
            storage_backend: "invalid".to_string(),
            auth_token: None,
            mount_point: "transit".to_string(),
            key_name: "test-key".to_string(),
            tls_verify: false,
            deployment_mode: DeploymentMode::Service,
        };

        assert!(config.validate().is_err());
    }

    #[test]
    fn test_config_validation_empty_mount_point() {
        let config = SecretumVaultConfig {
            server_url: "http://localhost:8200".to_string(),
            storage_backend: "filesystem".to_string(),
            auth_token: None,
            mount_point: String::new(),
            key_name: "test-key".to_string(),
            tls_verify: false,
            deployment_mode: DeploymentMode::Service,
        };

        assert!(config.validate().is_err());
    }

    #[test]
    fn test_deployment_mode_default() {
        let mode = DeploymentMode::default();
        assert_eq!(mode, DeploymentMode::Service); // Unless PROVISIONING_ENV=dev
    }
}
