use super::error::ConfigFieldPath;
use super::source::EnvName;

/// Config field source
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ConfigValueSource {
    File,
    Env(EnvName),
}

/// Config field requirement
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ConfigRequirement {
    Required,
    Optional,
    Defaulted,
}

/// One generated config field
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ConfigSchemaField {
    path: ConfigFieldPath,
    source: ConfigValueSource,
    requirement: ConfigRequirement,
}

impl ConfigSchemaField {
    /// Config field metadata
    pub fn new(
        path: ConfigFieldPath,
        source: ConfigValueSource,
        requirement: ConfigRequirement,
    ) -> Self {
        Self {
            path,
            source,
            requirement,
        }
    }

    /// Dotted field path
    pub fn path(&self) -> &ConfigFieldPath {
        &self.path
    }

    /// Declared source
    pub fn source(&self) -> &ConfigValueSource {
        &self.source
    }

    /// Requirement
    pub fn requirement(&self) -> ConfigRequirement {
        self.requirement
    }
}

/// Generated config schema
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct ConfigSchema {
    fields: Vec<ConfigSchemaField>,
}

impl ConfigSchema {
    /// Empty schema
    pub fn new() -> Self {
        Self { fields: Vec::new() }
    }

    /// Add one field
    pub fn push(&mut self, field: ConfigSchemaField) {
        self.fields.push(field);
    }

    /// Generated fields
    pub fn fields(&self) -> &[ConfigSchemaField] {
        &self.fields
    }

    #[doc(hidden)]
    pub fn extend(&mut self, fields: impl IntoIterator<Item = ConfigSchemaField>) {
        self.fields.extend(fields);
    }
}
