#[cfg(test)]
use crate::session::SessionIdentity;

#[cfg(all(target_family = "wasm", target_os = "unknown"))]
pub const AUTH_BROADCAST_CHANNEL: &str = "polymodel-auth";
#[cfg(all(target_family = "wasm", target_os = "unknown"))]
pub const SIGN_OUT_MESSAGE: &str = "sign-out";

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Toast {
    pub id: u64,
    pub message: String,
}

#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct ToastState {
    next_id: u64,
    items: Vec<Toast>,
}

impl ToastState {
    pub fn push(&mut self, message: impl Into<String>) -> u64 {
        let id = self.next_id;
        self.next_id += 1;
        self.items.push(Toast {
            id,
            message: message.into(),
        });
        id
    }

    pub fn dismiss(&mut self, id: u64) {
        self.items.retain(|toast| toast.id != id);
    }

    pub fn items(&self) -> &[Toast] {
        &self.items
    }
}

#[cfg(test)]
pub fn handle_remote_sign_out(session: &mut SessionIdentity, toasts: &mut ToastState) {
    *session = SessionIdentity::Anonymous;
    toasts.push("Signed out in another tab.");
}

pub fn logout_url() -> &'static str {
    "/oauth/logout"
}

#[cfg(all(target_family = "wasm", target_os = "unknown"))]
pub fn broadcast_sign_out() {
    if let Ok(channel) = web_sys::BroadcastChannel::new(AUTH_BROADCAST_CHANNEL) {
        let _ = channel.post_message(&wasm_bindgen::JsValue::from_str(SIGN_OUT_MESSAGE));
    }
}

#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
pub fn broadcast_sign_out() {}

#[cfg(test)]
mod tests {
    use super::*;
    use jacquard::types::string::Handle;
    use jacquard_common::types::did::Did;

    #[test]
    fn remote_sign_out_clears_session_and_adds_toast() {
        let mut session = SessionIdentity::Authenticated(crate::session::AuthenticatedIdentity {
            avatar: None,
            did: Did::new_owned("did:plc:alice").unwrap(),
            handle: Handle::new_owned("alice.test").unwrap(),
            display_name: None,
        });
        let mut toasts = ToastState::default();

        handle_remote_sign_out(&mut session, &mut toasts);

        assert_eq!(session, SessionIdentity::Anonymous);
        assert_eq!(toasts.items()[0].message, "Signed out in another tab.");
    }

    #[test]
    fn toast_state_dismisses_by_id() {
        let mut toasts = ToastState::default();
        let first = toasts.push("one");
        let _second = toasts.push("two");

        toasts.dismiss(first);

        assert_eq!(toasts.items().len(), 1);
        assert_eq!(toasts.items()[0].message, "two");
    }
}
