//! 邮件实时推送 Hub：邮箱地址 -> 订阅者。
//!
//! SMTP 收信后调用 [`MailHub::notify`]，所有通过 WebSocket 订阅该地址的客户端
//! 都会收到新邮件通知。基于 tokio broadcast channel，无订阅者时通知静默丢弃。

use dashmap::DashMap;
use std::sync::Arc;
use tokio::sync::broadcast;

const CHANNEL_CAPACITY: usize = 16;

#[derive(Clone, Default)]
pub struct MailHub {
    senders: Arc<DashMap<String, broadcast::Sender<String>>>,
}

impl MailHub {
    pub fn new() -> Self {
        Self::default()
    }

    /// 订阅某地址（WebSocket 升级时调用），返回接收端。
    pub fn subscribe(&self, address: &str) -> broadcast::Receiver<String> {
        self.senders
            .entry(address.to_lowercase())
            .or_insert_with(|| broadcast::channel::<String>(CHANNEL_CAPACITY).0)
            .subscribe()
    }

    /// 通知某地址有新邮件（payload 为序列化后的 JSON 字符串）。
    pub fn notify(&self, address: &str, payload: &str) {
        if let Some(tx) = self.senders.get(&address.to_lowercase()) {
            let _ = tx.send(payload.to_string());
        }
    }

    /// 清理无订阅者的通道。
    pub fn cleanup(&self, address: &str) {
        let should_remove = self
            .senders
            .get(&address.to_lowercase())
            .map(|tx| tx.receiver_count() == 0)
            .unwrap_or(false);
        if should_remove {
            self.senders.remove(&address.to_lowercase());
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn notify_delivers_to_subscriber() {
        let hub = MailHub::new();
        let mut rx = hub.subscribe("abc@shenjianl.cn");
        hub.notify("ABC@shenjianl.cn", "hello"); // 大小写不敏感
        assert_eq!(rx.recv().await.unwrap(), "hello");
    }

    #[tokio::test]
    async fn notify_without_subscriber_is_silent() {
        let hub = MailHub::new();
        // 无订阅者时不应 panic
        hub.notify("none@shenjianl.cn", "x");
    }
}
