use async_trait::async_trait;
use k8s_openapi::NamespaceResourceScope;
use kube::Resource;
use serde::{Serialize, de::DeserializeOwned};

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

#[derive(Debug, Clone, Serialize)]
pub struct K8sResourceScore<K: Resource + std::fmt::Debug> {
    pub resource: Vec<K>,
}

impl<K: Resource + std::fmt::Debug> K8sResourceScore<K> {
    pub fn single(resource: K) -> Self {
        Self {
            resource: vec![resource],
        }
    }
}

impl<
    K: Resource<Scope = NamespaceResourceScope>
        + std::fmt::Debug
        + Sync
        + DeserializeOwned
        + Default
        + serde::Serialize
        + 'static
        + Send
        + Clone,
    T: Topology,
> Score<T> for K8sResourceScore<K>
where
    <K as kube::Resource>::DynamicType: Default,
{
    fn create_interpret(&self) -> Box<dyn Interpret<T>> {
        todo!()
    }

    fn name(&self) -> String {
        "K8sResourceScore".to_string()
    }
}

#[derive(Debug)]
pub struct K8sResourceInterpret<K: Resource + std::fmt::Debug + Sync + Send> {
    pub score: K8sResourceScore<K>,
}

#[async_trait]
impl<
    K: Resource<Scope = NamespaceResourceScope>
        + Clone
        + std::fmt::Debug
        + DeserializeOwned
        + serde::Serialize
        + Default
        + Send
        + Sync,
    T: Topology + K8sclient,
> Interpret<T> for K8sResourceInterpret<K>
where
    <K as kube::Resource>::DynamicType: Default,
{
    async fn execute(
        &self,
        _inventory: &Inventory,
        topology: &T,
    ) -> Result<Outcome, InterpretError> {
        topology
            .k8s_client()
            .await
            .expect("Environment should provide enough information to instanciate a client")
            .apply_namespaced(&self.score.resource)
            .await?;

        Ok(Outcome::success(
            "Successfully applied resource".to_string(),
        ))
    }
    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!()
    }
}
