//
// Copyright (C) 2025 Automated Design Corp.. All Rights Reserved.
// Created Date: 2025-02-18 13:59:17
// -----
// Last Modified: 2025-02-25 06:56:26
// -----
//
//

use async_trait::async_trait;
use tokio::sync::{mpsc, oneshot};

use super::filter::SubscriptionFilter;

/// A struct representing a subscription broadcast, containing the topic, message,
/// and subscription information.
#[derive(Clone, Debug)]
pub struct SubscriptionBroadcast<R> {
    pub id: usize,
    pub topic: String,
    pub message: R,
}

#[derive(Clone, Debug)]
pub struct SubscriptionResponse {
    pub id: usize,
}

/// A type alias for the subscription broadcast sender.
pub type SubscriptionBroadcastTx<R> = mpsc::Sender<SubscriptionBroadcast<R>>;
/// A type alias for the subscription broadcast receiver.
pub type SubscriptionBroadcastRx<R> = mpsc::Receiver<SubscriptionBroadcast<R>>;

/// A type alias for the subscription response receiver.
pub type SubscriptionResponseTx = oneshot::Sender<SubscriptionResponse>;

/// A trait that defines the behavior for handling subscriptions. The intended use
/// is for async nodes to register and manage subscriptions in a generic way.
#[async_trait]
pub trait SubscriptionHandler<R>
where
    R: Clone + Send + 'static,
{
    /// Subscribe to a topic or event. Any message broadcast to the topic will be sent to the subscriber.
    ///
    /// # Parameters
    /// - `topic`: The topic or event to subscribe to.
    /// - `subscription_information`: Information related to the subscription.
    /// - `broadcast_tx`: The broadcast channel to send messages to the subscriber.
    /// - `respond_to`: The channel to send a response to acknowledge the subscription.
    async fn subscribe(&mut self, topic: String, respond_to: SubscriptionResponseTx);

    /// Subscribe to a topic or event with a filter. The filter will be used to determine if a message
    /// should be sent to the subscriber when an event on the topic occurs.
    ///
    /// # Parameters
    /// - `topic`: The topic or event to subscribe to.
    /// - `subscription_information`: Information related to the subscription.
    /// - `filter`: The filter to apply to the subscription.
    /// - `broadcast_tx`: The broadcast channel to send messages to the subscriber.
    /// - `respond_to`: The channel to send a response to acknowledge the subscription.
    async fn subscribe_with_filter(
        &mut self,
        topic: String,
        filter: Box<dyn SubscriptionFilter<R> + Send + Sync>,
        respond_to: SubscriptionResponseTx,
    );

    /// Unsubscribe from a topic or event.
    ///
    /// # Parameters
    /// - `topic`: The topic or event to unsubscribe from.
    /// - `subscription_information`: Information related to the subscription.
    /// - `respond_to`: The channel to send a response to acknowledge the unsubscription.
    async fn unsubscribe(&mut self, id: usize, respond_to: SubscriptionResponseTx);

    /// Broadcast a message to all subscribers of a topic.
    ///
    /// # Parameters
    /// - `topic`: The topic to broadcast the message to.
    /// - `message`: The message to broadcast.
    ///
    /// # Returns
    /// - `Result<(), anyhow::Error>`: Returns an error if the broadcast fails.
    async fn broadcast(&self, topic: String, message: R) -> Result<(), anyhow::Error>;
}
