use std::collections::BTreeMap;

use crate::{
    config::AppConfig,
    net::{tools::Packet, AClient, NetError, ServiceType},
};

pub struct ServiceBox {
    services: BTreeMap<u32, (ServiceType, AClient)>,
}

pub enum ServiceQualifier {
    Type(ServiceType),
    AppId(u32),
}

impl ServiceBox {
    pub fn new(own_app_id: u32, applications: &BTreeMap<ServiceType, Vec<AppConfig>>) -> Self {
        let mut services = BTreeMap::new();

        for (ty, apps) in applications.iter() {
            apps.iter().for_each(|a| {
                services.insert(
                    a.app_id,
                    (*ty, AClient::new(a.inner_ip.clone(), own_app_id)),
                );
            });
        }

        Self { services }
    }

    pub async fn push_packet_to_service(
        &self,
        qualifier: ServiceQualifier,
        packet: Packet,
    ) -> Result<(), NetError> {
        let client = match qualifier {
            ServiceQualifier::AppId(id) => {
                &self.services.get(&id).ok_or(NetError::MissingAppId(id))?.1
            }
            ServiceQualifier::Type(svc_type) => {
                &self
                    .services
                    .values()
                    .find(|(ty, _)| *ty == svc_type)
                    .ok_or(NetError::MissingAppId(0))?
                    .1
            }
        };

        client.send_packet(packet).await
    }

    pub fn push_packet_to_service_blocking(
        &self,
        qualifier: ServiceQualifier,
        packet: Packet,
    ) -> Result<(), NetError> {
        let client = match qualifier {
            ServiceQualifier::AppId(id) => {
                &self.services.get(&id).ok_or(NetError::MissingAppId(id))?.1
            }
            ServiceQualifier::Type(svc_type) => {
                &self
                    .services
                    .values()
                    .find(|(ty, _)| *ty == svc_type)
                    .ok_or(NetError::MissingAppId(0))?
                    .1
            }
        };

        client.send_packet_blocking(packet)
    }
}
