use serde::Deserialize;

const DEFAULT_PORT: u16 = 8090;

const DEFAULT_LIFETIME: u64 = 600;

#[derive(Debug, Clone, Deserialize)]
pub struct AppConfig {
    port: Option<u16>,
    sources_path: Option<String>,
    local_list_path: Option<String>,
    source_lifetime: Option<u64>,
}

impl AppConfig {
    pub fn new() -> Result<Self, Error> {
        let reader = config::Config::builder()
            .add_source(config::Environment::default())
            .build()
            .map_err(|e| {
                tracing::error!("{e}");
                Error::Builder
            })?;

        let config: Self = reader.try_deserialize().map_err(|e| {
            tracing::error!("{e}");
            Error::Read
        })?;

        if config.sources_path.is_none() && config.local_list_path.is_none() {
            Err(Error::MissingList)
        } else {
            Ok(config)
        }
    }

    pub fn port(&self) -> u16 {
        self.port.unwrap_or(DEFAULT_PORT)
    }

    pub fn sources_path(&self) -> Option<&str> {
        self.sources_path.as_deref()
    }

    pub fn local_list_path(&self) -> Option<&str> {
        self.local_list_path.as_deref()
    }

    pub fn source_lifetime(&self) -> u64 {
        self.source_lifetime.unwrap_or(DEFAULT_LIFETIME)
    }
}

#[derive(Debug, thiserror::Error)]
pub enum Error {
    #[error("failed to create builder to read configuration from environment")]
    Builder,

    #[error("failed to read required configuration from environment")]
    Read,

    #[error("we need at least one source, but none was provided")]
    MissingList,
}
