use std::fmt;
use std::sync::{Arc, RwLock};

#[derive(Clone, Debug)]
pub struct AuthToken(Arc<RwLock<String>>);

impl AuthToken {
    pub fn new(initial: impl Into<String>) -> Self {
        Self(Arc::new(RwLock::new(initial.into())))
    }

    pub fn set(&self, token: impl Into<String>) {
        *self
            .0
            .write()
            .expect("AuthToken RwLock write lock poisoned in set()") = token.into();
    }

    pub fn get(&self) -> String {
        self.0
            .read()
            .expect("AuthToken RwLock read lock poisoned in get()")
            .clone()
    }
}

impl fmt::Display for AuthToken {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let token = self.get();

        if token.is_empty() {
            write!(f, "<empty-auth-token>")
        } else if token.len() <= 6 {
            write!(f, "<auth-token:{}>", "*".repeat(token.len()))
        } else {
            let prefix = &token[..3];
            let suffix = &token[token.len() - 3..];
            write!(f, "<auth-token:{}…{}>", prefix, suffix)
        }
    }
}
