use serde::Deserialize;

#[derive(Debug, Deserialize, Clone, PartialEq)]
pub enum BlobStorageType {
    #[serde(rename = "local")]
    Local,
    #[serde(rename = "s3")]
    S3,
}

#[derive(Debug, Deserialize, Clone)]
pub struct Config {
    #[serde(default = "default_blob_storage_type")]
    pub blob_storage_type: BlobStorageType,
    #[serde(skip_serializing_if = "Option::is_none", flatten)]
    pub local_config: Option<LocalConfig>,
    #[serde(skip_serializing_if = "Option::is_none", flatten)]
    pub s3_config: Option<S3Config>,
}

#[derive(Debug, Deserialize, Clone)]
pub struct LocalConfig {
    #[serde(default = "default_storage_base_path")]
    pub storage_base_path: String,
}

impl LocalConfig {
    pub fn from_env() -> Result<Self, config::ConfigError> {
        let cfg = config::Config::builder()
            .add_source(config::Environment::default().separator(""))
            .build()
            .unwrap()
            .try_deserialize::<LocalConfig>()?;
        Ok(cfg)
    }
}
fn default_storage_base_path() -> String {
    "volume/data".to_string()
}

fn default_blob_storage_type() -> BlobStorageType {
    BlobStorageType::Local
}

#[derive(Debug, Deserialize, Clone)]
pub struct S3Config {
    pub s3_endpoint_url: String,
    pub s3_bucket_name: String,
    pub s3_access_key_id: String,
    pub s3_secret_access_key: String,
    #[serde(default = "default_s3_path_prefix")]
    pub s3_path_prefix: String,
    pub cdn_url: Option<String>,
    pub s3_region: String,
}

impl S3Config {
    pub fn from_env() -> Result<Self, config::ConfigError> {
        let cfg = config::Config::builder()
            .add_source(config::Environment::default().separator(""))
            .build()
            .unwrap()
            .try_deserialize::<S3Config>()?;
        Ok(cfg)
    }
}

fn default_s3_path_prefix() -> String {
    "cactus-backend".to_string()
}

impl Config {
    pub fn from_env() -> Result<Self, config::ConfigError> {
        let blob_storage_type = std::env::var("BLOB_STORAGE_TYPE").unwrap_or("local".to_string());
        if blob_storage_type == "s3" {
            let s3_config = S3Config::from_env()?;
            Ok(Config {
                blob_storage_type: BlobStorageType::S3,
                s3_config: Some(s3_config),
                local_config: None,
            })
        } else if blob_storage_type == "local" {
            let local_config = LocalConfig::from_env()?;
            Ok(Config {
                blob_storage_type: BlobStorageType::Local,
                s3_config: None,
                local_config: Some(local_config),
            })
        } else {
            Err(config::ConfigError::Message(format!("Invalid blob storage type: {}", blob_storage_type)))
        }
    }
}
