use std::error::Error;

use axum::{extract::Request, ServiceExt};
use common::db::{self, DbDeployConfigMgr};
use tokio::net::TcpListener;

use crate::{
    config::DispatchConfig,
    dispatch_service,
    gateserver_mgr::GateserverMgr,
    network::{self, NetworkMgr},
};

pub struct DispatchService {
    pub config: DispatchConfig,
    pub network_mgr: NetworkMgr,
    pub db_deploy_config_mgr: DbDeployConfigMgr,
    pub gateserver_mgr: GateserverMgr,
}

impl DispatchService {
    pub async fn new(config: DispatchConfig) -> Result<Self, Box<dyn Error>> {
        let db_pool = db::connect(&config.database.connection_string).await?;
        let network_mgr = NetworkMgr::new(&config).await?;
        let gateserver_mgr = GateserverMgr::new();

        Ok(Self {
            config,
            network_mgr,
            gateserver_mgr,
            db_deploy_config_mgr: DbDeployConfigMgr::new(db_pool),
        })
    }

    pub async fn run(&self) {
        tokio::spawn(async {
            let router = network::http_handlers::make_routes();

            let listener = TcpListener::bind(&dispatch_service().config.net.http.bind_host)
                .await
                .unwrap();

            axum::serve(listener, ServiceExt::<Request>::into_make_service(router)).await
        });

        self.network_mgr.run().await
    }
}
