use crate::config::idp_provider;
use miette::Diagnostic;
use thiserror::Error;

/// Errors that occur while building or loading config.
#[derive(Error, Debug, Diagnostic)]
pub enum ConfigError {
    #[error("ConfigError - Value [{0}] was not set")]
    ValueNotSet(&'static str),

    #[error("IO Error: file = {1} {0}")]
    Io(String, String),

    #[error("Invalid URL: {0}")]
    InvalidUrl(#[from] url::ParseError),

    #[diagnostic(transparent)]
    #[error(transparent)]
    InvalidProvider(#[from] idp_provider::ParseError),

    /// Errors caused by invalid configuration provided by the user.
    #[error("Invalid config error: {0}")]
    InvalidConfigError(String),

    /// Returned when a source is not found (e.g. a file does not exist).
    #[error("Missing source: `{0}`")]
    NotFound(String),

    /// Error caused when the home directory can't be resolved
    #[error("{0}")]
    HomeDirError(String),

    #[error(transparent)]
    InvalidWorkspaceId(#[from] cts_common::InvalidWorkspaceId),

    #[error("Invalid workspace CRN: {0}")]
    #[diagnostic(transparent)]
    InvalidWorkspaceCrn(#[from] cts_common::InvalidCrn),

    #[error("Invalid region: {0}")]
    #[diagnostic(transparent)]
    InvalidRegion(#[from] cts_common::RegionError),
}

impl ConfigError {
    pub fn io<E: std::error::Error, P: AsRef<std::path::Path>>(e: E, file_path: P) -> Self {
        Self::Io(
            e.to_string(),
            file_path.as_ref().to_string_lossy().to_string(),
        )
    }

    pub fn invalid<E: std::fmt::Display>(e: E) -> Self {
        Self::InvalidConfigError(e.to_string())
    }
}
