use serde::Serialize;

use crate::{
    interpret::Interpret,
    inventory::Inventory,
    modules::dhcp::DhcpScore,
    score::Score,
    topology::{DhcpServer, HAClusterTopology, HostBinding, Topology},
};

#[derive(Debug, Clone, Serialize)]
pub struct OKDBootstrapDhcpScore {
    dhcp_score: DhcpScore,
}

impl OKDBootstrapDhcpScore {
    pub fn new(topology: &HAClusterTopology, inventory: &Inventory) -> Self {
        let mut host_binding: Vec<_> = topology
            .control_plane
            .iter()
            .enumerate()
            .map(|(index, topology_entry)| HostBinding {
                logical_host: topology_entry.clone(),
                physical_host: inventory
                    .control_plane_host
                    .get(index)
                    .expect("Iventory should contain at least as many physical hosts as topology")
                    .clone(),
            })
            .collect();
        host_binding.push(HostBinding {
            logical_host: topology.bootstrap_host.clone(),
            physical_host: inventory
                .worker_host
                .get(0)
                .expect("Should have at least one worker to be used as bootstrap node")
                .clone(),
        });
        // TODO refactor this so it is not copy pasted from dhcp.rs
        Self {
            dhcp_score: DhcpScore::new(
                host_binding,
                // TODO : we should add a tftp server to the topology instead of relying on the
                // router address, this is leaking implementation details
                Some(topology.router.get_gateway()),
                None, // To allow UEFI boot we cannot provide a legacy file
                Some("undionly.kpxe".to_string()),
                Some("ipxe.efi".to_string()),
                Some(format!(
                    "http://{}:8080/boot.ipxe",
                    topology.router.get_gateway()
                )),
            ),
        }
    }
}

impl<T: Topology + DhcpServer> Score<T> for OKDBootstrapDhcpScore {
    fn create_interpret(&self) -> Box<dyn Interpret<T>> {
        self.dhcp_score.create_interpret()
    }

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