use async_trait::async_trait;
use log::info;

use crate::{
    executors::ExecutorError,
    topology::{IpAddress, TftpServer, Url},
};

use super::OPNSenseFirewall;

#[async_trait]
impl TftpServer for OPNSenseFirewall {
    async fn serve_files(&self, url: &Url) -> Result<(), ExecutorError> {
        let tftp_root_path = "/usr/local/tftp";

        let config = self.opnsense_config.read().await;
        info!("Uploading files from url {url} to {tftp_root_path}");
        match url {
            Url::LocalFolder(path) => {
                config
                    .upload_files(path, tftp_root_path)
                    .await
                    .map_err(|e| ExecutorError::UnexpectedError(e.to_string()))?;
            }
            Url::Url(url) => todo!("This url is not supported yet {url}"),
        }
        Ok(())
    }

    fn get_ip(&self) -> IpAddress {
        todo!()
    }

    async fn set_ip(&self, ip: IpAddress) -> Result<(), ExecutorError> {
        info!("Setting listen_ip to {}", &ip);
        self.opnsense_config
            .write()
            .await
            .tftp()
            .listen_ip(&ip.to_string());
        Ok(())
    }

    async fn commit_config(&self) -> Result<(), ExecutorError> {
        OPNSenseFirewall::commit_config(self).await
    }

    async fn reload_restart(&self) -> Result<(), ExecutorError> {
        self.opnsense_config
            .write()
            .await
            .tftp()
            .reload_restart()
            .await
            .map_err(|e| ExecutorError::UnexpectedError(e.to_string()))
    }

    async fn ensure_initialized(&self) -> Result<(), ExecutorError> {
        let mut config = self.opnsense_config.write().await;
        let tftp = config.tftp();
        if let None = tftp.get_full_config() {
            info!("Tftp config not available in opnsense config, installing package");
            config.install_package("os-tftp").await.map_err(|e| {
                ExecutorError::UnexpectedError(format!(
                    "Executor failed when trying to install os-tftp package with error {e:?}"
                ))
            })?;
        } else {
            info!("Tftp config available in opnsense config, assuming it is already installed");
        }

        info!("Enabling tftp server");
        config.tftp().enable(true);

        Ok(())
    }
}
