pub mod features;
mod rust;
pub use rust::*;

use async_trait::async_trait;
use serde::Serialize;

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

#[derive(Debug)]
pub struct ApplicationInterpret<T: Topology + std::fmt::Debug> {
    features: Vec<Box<dyn ApplicationFeature<T>>>,
}

#[async_trait]
impl<T: Topology + std::fmt::Debug> Interpret<T> for ApplicationInterpret<T> {
    async fn execute(
        &self,
        _inventory: &Inventory,
        topology: &T,
    ) -> Result<Outcome, InterpretError> {
        for feature in self.features.iter() {
            let _ = match feature.ensure_installed(topology).await {
                Ok(()) => (),
                Err(msg) => {
                    return Err(InterpretError::new(format!(
                        "Application Interpret failed to install feature : {msg}"
                    )));
                }
            };
        }
        todo!("Do I need to do anything more than this here??")
    }

    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!()
    }
}

/// An ApplicationFeature provided by harmony, such as Backups, Monitoring, MultisiteAvailability,
/// ContinuousIntegration, ContinuousDelivery
#[async_trait]
pub trait ApplicationFeature<T: Topology>:
    std::fmt::Debug + Send + Sync + ApplicationFeatureClone<T>
{
    async fn ensure_installed(&self, topology: &T) -> Result<(), String>;
}

trait ApplicationFeatureClone<T: Topology> {
    fn clone_box(&self) -> Box<dyn ApplicationFeature<T>>;
}

impl<A, T: Topology> ApplicationFeatureClone<T> for A
where
    A: ApplicationFeature<T> + Clone + 'static,
{
    fn clone_box(&self) -> Box<dyn ApplicationFeature<T>> {
        Box::new(self.clone())
    }
}

impl<T: Topology> Serialize for Box<dyn ApplicationFeature<T>> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        todo!()
    }
}

impl<T: Topology> Clone for Box<dyn ApplicationFeature<T>> {
    fn clone(&self) -> Self {
        self.clone_box()
    }
}
