use crate::client::interceptor::{ConnectionHook};
use crate::protocol::{Frame, ServerCommand};
use log::debug;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::Mutex;
use tokio::sync::mpsc::Sender;
use tokio::time::Duration;
use async_trait::async_trait;

type Subscribers = Arc<Mutex<HashMap<String, Sender<Frame<ServerCommand>>>>>;

#[derive(Clone)]
pub struct SubscriberHandler {
    subscribers: Subscribers,
}

impl SubscriberHandler {
    pub async fn new() -> Self {
        let subscribers: Subscribers =  Default::default();
        let subscribers_clone =  Arc::clone(&subscribers);

        tokio::spawn(async move {
            loop {
                tokio::time::sleep(Duration::from_secs(1)).await;

                let mut locked_subscribers = subscribers_clone.lock().await;

                let remove_subscribers: Vec<_> = locked_subscribers.iter()
                    .filter(|sub| !sub.1.is_closed())
                    .map(|sub| sub.0.clone())
                    .collect();

                for subscriber in remove_subscribers {
                    locked_subscribers.remove(&subscriber);
                }
            }
        });
        Self {
            subscribers
        }
    }

    pub async fn register(
        &self,
        subscriber_id: impl Into<String>,
        _destination: impl Into<String>,
        sender: Sender<Frame<ServerCommand>>
    ) {
        self.subscribers.lock()
            .await
            .insert(subscriber_id.into(), sender);
    }
}

#[async_trait]
impl ConnectionHook for SubscriberHandler {
    async fn before_receive(&self, frame: &Frame<ServerCommand>) {
        if let Some(subscription) = frame.headers.get("subscription") {
            let lock_subscribers = self.subscribers.lock().await;
            if let Some(sub_sender) = lock_subscribers.get(subscription) {
                if sub_sender.send(frame.clone()).await.is_err() {
                    debug!("Could not deliver message to subscriber {}", subscription)
                }
            }
        }
    }
}