use async_trait::async_trait;
use harmony_types::net::MacAddress;
use log::debug;

use crate::{
    executors::ExecutorError,
    topology::{DHCPStaticEntry, DhcpServer, IpAddress, LogicalHost},
};

use super::OPNSenseFirewall;

#[async_trait]
impl DhcpServer for OPNSenseFirewall {
    async fn commit_config(&self) -> Result<(), ExecutorError> {
        OPNSenseFirewall::commit_config(self).await
    }

    async fn add_static_mapping(&self, entry: &DHCPStaticEntry) -> Result<(), ExecutorError> {
        let mac: String = String::from(&entry.mac);

        {
            let mut writable_opnsense = self.opnsense_config.write().await;
            writable_opnsense
                .dhcp()
                .add_static_mapping(&mac, entry.ip, &entry.name)
                .unwrap();
        }

        debug!("Registered {:?}", entry);
        Ok(())
    }

    async fn remove_static_mapping(&self, _mac: &MacAddress) -> Result<(), ExecutorError> {
        todo!()
    }

    async fn list_static_mappings(&self) -> Vec<(MacAddress, IpAddress)> {
        todo!()
    }

    fn get_ip(&self) -> IpAddress {
        OPNSenseFirewall::get_ip(self)
    }

    fn get_host(&self) -> LogicalHost {
        self.host.clone()
    }

    async fn set_next_server(&self, ip: IpAddress) -> Result<(), ExecutorError> {
        let ipv4 = match ip {
            std::net::IpAddr::V4(ipv4_addr) => ipv4_addr,
            std::net::IpAddr::V6(_) => todo!("ipv6 not supported yet"),
        };
        {
            let mut writable_opnsense = self.opnsense_config.write().await;
            writable_opnsense.dhcp().set_next_server(ipv4);
            debug!("OPNsense dhcp server set next server {ipv4}");
        }

        Ok(())
    }

    async fn set_boot_filename(&self, boot_filename: &str) -> Result<(), ExecutorError> {
        {
            let mut writable_opnsense = self.opnsense_config.write().await;
            writable_opnsense.dhcp().set_boot_filename(boot_filename);
            debug!("OPNsense dhcp server set boot filename {boot_filename}");
        }

        Ok(())
    }

    async fn set_filename(&self, filename: &str) -> Result<(), ExecutorError> {
        {
            let mut writable_opnsense = self.opnsense_config.write().await;
            writable_opnsense.dhcp().set_filename(filename);
            debug!("OPNsense dhcp server set filename {filename}");
        }

        Ok(())
    }

    async fn set_filename64(&self, filename: &str) -> Result<(), ExecutorError> {
        {
            let mut writable_opnsense = self.opnsense_config.write().await;
            writable_opnsense.dhcp().set_filename64(filename);
            debug!("OPNsense dhcp server set filename {filename}");
        }

        Ok(())
    }

    async fn set_filenameipxe(&self, filenameipxe: &str) -> Result<(), ExecutorError> {
        {
            let mut writable_opnsense = self.opnsense_config.write().await;
            writable_opnsense.dhcp().set_filenameipxe(filenameipxe);
            debug!("OPNsense dhcp server set filenameipxe {filenameipxe}");
        }

        Ok(())
    }
}
