use std::sync::Arc;

use opnsense_config_xml::{OPNsense, Tftp};

use crate::{config::OPNsenseShell, Error};

pub struct TftpConfig<'a> {
    opnsense: &'a mut OPNsense,
    opnsense_shell: Arc<dyn OPNsenseShell>,
}

impl<'a> TftpConfig<'a> {
    pub fn new(opnsense: &'a mut OPNsense, opnsense_shell: Arc<dyn OPNsenseShell>) -> Self {
        Self {
            opnsense,
            opnsense_shell,
        }
    }

    pub fn get_full_config(&self) -> &Option<Tftp> {
        &self.opnsense.opnsense.tftp
    }

    fn with_tftp<F, R>(&mut self, f: F) -> R
    where
        F: FnOnce(&mut Tftp) -> R,
    {
        match &mut self.opnsense.opnsense.tftp.as_mut() {
            Some(tftp) => f(tftp),
            None => unimplemented!("Accessing tftp config is not supported when not available yet"),
        }
    }

    pub fn enable(&mut self, enabled: bool) {
        self.with_tftp(|tftp| tftp.general.enabled = enabled as u8);
    }

    pub fn listen_ip(&mut self, ip: &str) {
        self.with_tftp(|tftp| tftp.general.listen = ip.to_string());
    }

    pub async fn reload_restart(&self) -> Result<(), Error> {
        self.opnsense_shell.exec("configctl tftp stop").await?;
        self.opnsense_shell
            .exec("configctl template reload OPNsense/Tftp")
            .await?;
        self.opnsense_shell.exec("configctl tftp start").await?;
        Ok(())
    }
}
