use async_trait::async_trait;
use derive_new::new;
use serde::Serialize;

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

#[derive(Debug, new, Clone, Serialize)]
pub struct TftpScore {
    files_to_serve: Url,
}

impl<T: Topology + TftpServer + Router> Score<T> for TftpScore {
    fn create_interpret(&self) -> Box<dyn Interpret<T>> {
        Box::new(TftpInterpret::new(self.clone()))
    }

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

#[derive(Debug, new, Clone)]
pub struct TftpInterpret {
    score: TftpScore,
}

#[async_trait]
impl<T: Topology + TftpServer + Router> Interpret<T> for TftpInterpret {
    async fn execute(
        &self,
        _inventory: &Inventory,
        topology: &T,
    ) -> Result<Outcome, InterpretError> {
        topology.ensure_initialized().await?;
        topology.set_ip(topology.get_gateway()).await?;
        topology.serve_files(&self.score.files_to_serve).await?;
        topology.commit_config().await?;
        topology.reload_restart().await?;
        Ok(Outcome::success(format!(
            "TFTP Server running and serving files from {}",
            self.score.files_to_serve
        )))
    }

    fn get_name(&self) -> InterpretName {
        InterpretName::Tftp
    }

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

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

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