use async_trait::async_trait;
use log::debug;

use crate::{
    data::{Id, Version},
    interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome},
    inventory::Inventory,
    topology::{Topology, installable::Installable},
};

#[async_trait]
pub trait AlertSender: Send + Sync + std::fmt::Debug {
    fn name(&self) -> String;
}

#[derive(Debug)]
pub struct AlertingInterpret<S: AlertSender> {
    pub sender: S,
    pub receivers: Vec<Box<dyn AlertReceiver<S>>>,
    pub rules: Vec<Box<dyn AlertRule<S>>>,
}

#[async_trait]
impl<S: AlertSender + Installable<T>, T: Topology> Interpret<T> for AlertingInterpret<S> {
    async fn execute(
        &self,
        inventory: &Inventory,
        topology: &T,
    ) -> Result<Outcome, InterpretError> {
        for receiver in self.receivers.iter() {
            receiver.install(&self.sender).await?;
        }
        for rule in self.rules.iter() {
            debug!("installing rule: {:#?}", rule);
            rule.install(&self.sender).await?;
        }
        self.sender.ensure_installed(inventory, topology).await?;
        Ok(Outcome::success(format!(
            "successfully installed alert sender {}",
            self.sender.name()
        )))
    }

    fn get_name(&self) -> InterpretName {
        todo!()
    }

    fn get_version(&self) -> Version {
        todo!()
    }

    fn get_status(&self) -> InterpretStatus {
        todo!()
    }

    fn get_children(&self) -> Vec<Id> {
        todo!()
    }
}

#[async_trait]
pub trait AlertReceiver<S: AlertSender>: std::fmt::Debug + Send + Sync {
    async fn install(&self, sender: &S) -> Result<Outcome, InterpretError>;
    fn clone_box(&self) -> Box<dyn AlertReceiver<S>>;
}

#[async_trait]
pub trait AlertRule<S: AlertSender>: std::fmt::Debug + Send + Sync {
    async fn install(&self, sender: &S) -> Result<Outcome, InterpretError>;
    fn clone_box(&self) -> Box<dyn AlertRule<S>>;
}

#[async_trait]
pub trait ScrapeTarger<S: AlertSender> {
    async fn install(&self, sender: &S) -> Result<(), InterpretError>;
}
