use std::{error::Error, sync::Arc};

use commands::CommandManager;
use common::{init_tracing, splash, util::load_or_create_config};
use config::NapGSConfig;
use data::init_data;
use logic::player::PlayerManager;
use net::NetSessionManager;
use rustyline_async::Readline;

mod commands;
mod config;
mod database;
mod handlers;
mod logic;
mod net;

pub struct ServerState {
    pub session_mgr: NetSessionManager,
    pub player_mgr: PlayerManager,
    pub config: NapGSConfig,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    splash::print("GameServer");

    let rl = Readline::new(String::from(">> ")).ok();
    init_tracing(rl.as_ref().map(|(_, out)| out.clone()));

    tracing::info!("don't forget to visit https://discord.xeondev.com/");

    let config = load_or_create_config::<NapGSConfig>("nap_gameserver.toml");
    init_data(&config.assets).expect("failed to init data");

    let pg_pool = common::database::init(&config.database_credentials)
        .await
        .expect("failed to connect to database");

    let state = Arc::new(ServerState {
        session_mgr: NetSessionManager::new(),
        player_mgr: PlayerManager::new(pg_pool),
        config,
    });

    if let Some((rl, out)) = rl {
        let command_mgr = CommandManager::new(state.clone());
        tokio::spawn(async move { command_mgr.run(rl, out).await });
    }

    net::listen(state).await
}
