use std::net::SocketAddr;

use serde::Serialize;

use crate::{
    interpret::Interpret,
    modules::load_balancer::LoadBalancerScore,
    score::Score,
    topology::{
        BackendServer, HAClusterTopology, HealthCheck, HttpMethod, HttpStatusCode, LoadBalancer,
        LoadBalancerService, Topology,
    },
};

impl std::fmt::Display for OKDLoadBalancerScore {
    fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        todo!()
    }
}

#[derive(Debug, Clone, Serialize)]
pub struct OKDLoadBalancerScore {
    load_balancer_score: LoadBalancerScore,
}

impl OKDLoadBalancerScore {
    pub fn new(topology: &HAClusterTopology) -> Self {
        let public_ip = topology.router.get_gateway();
        let public_services = vec![
            LoadBalancerService {
                backend_servers: Self::control_plane_to_backend_server(topology, 80),
                listening_port: SocketAddr::new(public_ip, 80),
                health_check: Some(HealthCheck::TCP(None)),
            },
            LoadBalancerService {
                backend_servers: Self::control_plane_to_backend_server(topology, 443),
                listening_port: SocketAddr::new(public_ip, 443),
                health_check: Some(HealthCheck::TCP(None)),
            },
        ];

        let private_services = vec![
            LoadBalancerService {
                backend_servers: Self::control_plane_to_backend_server(topology, 80),
                listening_port: SocketAddr::new(public_ip, 80),
                health_check: Some(HealthCheck::TCP(None)),
            },
            LoadBalancerService {
                backend_servers: Self::control_plane_to_backend_server(topology, 443),
                listening_port: SocketAddr::new(public_ip, 443),
                health_check: Some(HealthCheck::TCP(None)),
            },
            LoadBalancerService {
                backend_servers: Self::control_plane_to_backend_server(topology, 22623),
                listening_port: SocketAddr::new(public_ip, 22623),
                health_check: Some(HealthCheck::TCP(None)),
            },
            LoadBalancerService {
                backend_servers: Self::control_plane_to_backend_server(topology, 6443),
                listening_port: SocketAddr::new(public_ip, 6443),
                health_check: Some(HealthCheck::HTTP(
                    "/readyz".to_string(),
                    HttpMethod::GET,
                    HttpStatusCode::Success2xx,
                )),
            },
        ];
        Self {
            load_balancer_score: LoadBalancerScore {
                public_services,
                private_services,
            },
        }
    }

    fn control_plane_to_backend_server(
        topology: &HAClusterTopology,
        port: u16,
    ) -> Vec<BackendServer> {
        topology
            .control_plane
            .iter()
            .map(|cp| BackendServer {
                address: cp.ip.to_string(),
                port,
            })
            .collect()
    }
}

impl<T: Topology + LoadBalancer> Score<T> for OKDLoadBalancerScore {
    fn create_interpret(&self) -> Box<dyn Interpret<T>> {
        self.load_balancer_score.create_interpret()
    }

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