use crate::{KvVersion, VaultAddr, VaultConfig, VaultSource};

#[cfg(feature = "tls")]
use crate::TlsConfig;

#[derive(Debug)]
pub struct VaultSourceBuilder {
    address: Option<String>,
    token: Option<String>,
    mount: Option<String>,
    path: Option<String>,
    kv_version: KvVersion,

    #[cfg(feature = "tls")]
    tls: Option<TlsConfig>,
}

impl VaultSourceBuilder {
    pub fn new() -> Self {
        Self {
            ..Default::default()
        }
    }

    pub fn address(mut self, address: impl Into<String>) -> Self {
        self.address = Some(address.into());
        self
    }

    pub fn token(mut self, token: impl Into<String>) -> Self {
        self.token = Some(token.into());
        self
    }

    pub fn mount(mut self, mount: impl Into<String>) -> Self {
        self.mount = Some(mount.into());
        self
    }

    pub fn path(mut self, path: impl Into<String>) -> Self {
        self.path = Some(path.into());
        self
    }

    pub fn kv_version(mut self, version: KvVersion) -> Self {
        self.kv_version = version;
        self
    }

    #[cfg(feature = "tls")]
    pub fn tls(mut self, tls: TlsConfig) -> Self {
        self.tls = Some(tls);
        self
    }

    pub fn build(self) -> Result<VaultSource, config::ConfigError> {
        let address = self.address.ok_or(config::ConfigError::Message(
            "Vault address must present".to_string(),
        ))?;

        let parsed_addr = VaultAddr::try_from(address)?;

        let mount = self.mount.ok_or(config::ConfigError::Message(
            "Vault mount point must present".to_string(),
        ))?;

        let path = self.path.ok_or(config::ConfigError::Message(
            "Vault config path must present".to_string(),
        ))?;

        let token = self.token.ok_or(config::ConfigError::Message(
            "Vault config path must present".to_string(),
        ))?;

        let config = VaultConfig {
            address: parsed_addr,
            token: token,
            mount,
            path,

            #[cfg(feature = "tls")]
            tls: self.tls,
        };

        Ok(VaultSource {
            config,
            kv_version: self.kv_version,
        })
    }
}

impl Default for VaultSourceBuilder {
    fn default() -> Self {
        Self {
            address: Some("http://127.0.0.1:8200".to_string()),
            token: Some("root".to_string()),
            mount: Some("secret".to_string()),
            path: Some("dev".to_string()),
            kv_version: Default::default(),

            #[cfg(feature = "tls")]
            tls: None,
        }
    }
}
