use std::sync::Arc;

use opnsense_config_xml::{Caddy, OPNsense, Pischem};

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

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

impl<'a> CaddyConfig<'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<Pischem> {
        &self.opnsense.pischem
    }

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

    pub fn enable(&mut self, enabled: bool) {
        self.with_caddy(|caddy| {
            caddy.general.enabled = enabled as u8;
            caddy.general.http_port = Some(8080);
            caddy.general.https_port = Some(8443);
        });
    }

    pub async fn reload_restart(&self) -> Result<(), Error> {
        self.opnsense_shell.exec("configctl caddy stop").await?;
        self.opnsense_shell
            .exec("configctl template reload OPNsense/Caddy")
            .await?;
        self.opnsense_shell
            .exec("configctl template reload OPNsense/Caddy/rc.conf.d")
            .await?;
        self.opnsense_shell.exec("configctl caddy validate").await?;
        self.opnsense_shell.exec("configctl caddy start").await?;
        Ok(())
    }
}
