use std::{
    net::{IpAddr, Ipv4Addr},
    sync::Arc,
};

use cidr::Ipv4Cidr;
use harmony::{
    hardware::{FirewallGroup, HostCategory, Location, PhysicalHost, SwitchGroup},
    infra::opnsense::OPNSenseManagementInterface,
    inventory::Inventory,
    maestro::Maestro,
    modules::{
        dummy::{ErrorScore, PanicScore, SuccessScore},
        http::HttpScore,
        okd::{dhcp::OKDDhcpScore, dns::OKDDnsScore, load_balancer::OKDLoadBalancerScore},
        opnsense::OPNsenseShellCommandScore,
        tftp::TftpScore,
    },
    topology::{LogicalHost, UnmanagedRouter, Url},
};
use harmony_macros::{ip, mac_address};

#[tokio::main]
async fn main() {
    let firewall = harmony::topology::LogicalHost {
        ip: ip!("192.168.5.229"),
        name: String::from("opnsense-1"),
    };

    let opnsense = Arc::new(
        harmony::infra::opnsense::OPNSenseFirewall::new(firewall, None, "root", "opnsense").await,
    );
    let lan_subnet = Ipv4Addr::new(10, 100, 8, 0);
    let gateway_ipv4 = Ipv4Addr::new(10, 100, 8, 1);
    let gateway_ip = IpAddr::V4(gateway_ipv4);
    let topology = harmony::topology::HAClusterTopology {
        domain_name: "demo.harmony.mcd".to_string(),
        router: Arc::new(UnmanagedRouter::new(
            gateway_ip,
            Ipv4Cidr::new(lan_subnet, 24).unwrap(),
        )),
        load_balancer: opnsense.clone(),
        firewall: opnsense.clone(),
        tftp_server: opnsense.clone(),
        http_server: opnsense.clone(),
        dhcp_server: opnsense.clone(),
        dns_server: opnsense.clone(),
        control_plane: vec![LogicalHost {
            ip: ip!("10.100.8.20"),
            name: "cp0".to_string(),
        }],
        bootstrap_host: LogicalHost {
            ip: ip!("10.100.8.20"),
            name: "cp0".to_string(),
        },
        workers: vec![],
        switch: vec![],
    };

    let inventory = Inventory {
        location: Location::new(
            "232 des Éperviers, Wendake, Qc, G0A 4V0".to_string(),
            "wk".to_string(),
        ),
        switch: SwitchGroup::from([]),
        firewall: FirewallGroup::from([PhysicalHost::empty(HostCategory::Firewall)
            .management(Arc::new(OPNSenseManagementInterface::new()))]),
        storage_host: vec![],
        worker_host: vec![],
        control_plane_host: vec![
            PhysicalHost::empty(HostCategory::Server)
                .mac_address(mac_address!("08:00:27:62:EC:C3")),
        ],
    };

    // TODO regroup smaller scores in a larger one such as this
    // let okd_boostrap_preparation();

    let dhcp_score = OKDDhcpScore::new(&topology, &inventory);
    let dns_score = OKDDnsScore::new(&topology);
    let load_balancer_score = OKDLoadBalancerScore::new(&topology);

    let tftp_score = TftpScore::new(Url::LocalFolder("./data/watchguard/tftpboot".to_string()));
    let http_score = HttpScore::new(Url::LocalFolder(
        "./data/watchguard/pxe-http-files".to_string(),
    ));
    let mut maestro = Maestro::new(inventory, topology);
    maestro.register_all(vec![
        Box::new(dns_score),
        Box::new(dhcp_score),
        Box::new(load_balancer_score),
        Box::new(tftp_score),
        Box::new(http_score),
        Box::new(OPNsenseShellCommandScore {
            opnsense: opnsense.get_opnsense_config(),
            command: "touch /tmp/helloharmonytouching".to_string(),
        }),
        Box::new(SuccessScore {}),
        Box::new(ErrorScore {}),
        Box::new(PanicScore {}),
    ]);
    harmony_tui::init(maestro).await.unwrap();
}
