use core::error::Error;

#[derive(Debug)]
pub enum IdGenError<T>
{
    /// Internal error when an ID has already been returned to the generator
    ///
    /// This is useful for determining areas in the code where IDs are
    /// erroneously being returned more than once. This can be an issue
    /// because when an ID is returned, it may be reused immediately.
    /// If a part of the code thinks that ID is still associated with
    /// something else, that can cause problems.
    DuplicateIdReturn(T),
    /// Invalid id has been provided to the generator.
    InvalidId(T),
    /// The generator has reached the maximum safe value for the type
    /// and can no longer increment to generate a new id.
    IdsExhausted(T),
}

impl<T> IdGenError<T> {
    /// Retrieves the id value which resulted in the error
    pub fn get_id(&self) -> &T {
        match self {
            Self::DuplicateIdReturn(id) => id,
            Self::InvalidId(id) => id,
            Self::IdsExhausted(id) => id,
        }
    }

    /// Whether this error indicates a duplicate id was returned
    pub fn is_duplicate_id_return(&self) -> bool {
        matches!(&self, Self::DuplicateIdReturn(_))
    }

    /// Whether this error indicates an invalid id was returned
    pub fn is_invalid_id(&self) -> bool {
        matches!(&self, Self::InvalidId(_))
    }

    /// Whether this error indicates ids are exhausted
    pub fn is_ids_exhausted(&self) -> bool {
        matches!(&self, Self::IdsExhausted(_))
    }
}

impl<T: core::fmt::Debug + core::fmt::Display> Error for IdGenError<T> {}

impl<T: core::fmt::Display> core::fmt::Display for IdGenError<T> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        match self {
            Self::DuplicateIdReturn(id) => {
                write!(f, "Id {} has already been returned", id)
            },
            Self::InvalidId(id) => {
                write!(f, "Invalid id {}", id)
            },
            Self::IdsExhausted(id) => {
                write!(f, "Maximum id value {} issued - no ids remaining", id)
            }
        }?;

        Ok(())
    }
}
