//! Shared context types for the peer system.

use std::{
    collections::{HashMap, HashSet},
    net::SocketAddr,
    sync::Arc,
};

use lanspread_db::db::GameDB;
use tokio::{sync::RwLock, task::JoinHandle};

use crate::{PeerEvent, peer_db::PeerGameDB};

/// Main context for the peer system.
#[derive(Clone)]
pub struct Ctx {
    pub game_dir: Arc<RwLock<Option<String>>>,
    pub local_game_db: Arc<RwLock<Option<GameDB>>>,
    pub peer_game_db: Arc<RwLock<PeerGameDB>>,
    pub local_peer_addr: Arc<RwLock<Option<SocketAddr>>>,
    pub downloading_games: Arc<RwLock<HashSet<String>>>,
    pub active_downloads: Arc<RwLock<HashMap<String, JoinHandle<()>>>>,
}

/// Context for peer connection handling.
#[derive(Clone)]
pub struct PeerCtx {
    pub game_dir: Arc<RwLock<Option<String>>>,
    pub local_game_db: Arc<RwLock<Option<GameDB>>>,
    pub local_peer_addr: Arc<RwLock<Option<SocketAddr>>>,
    pub downloading_games: Arc<RwLock<HashSet<String>>>,
    pub peer_game_db: Arc<RwLock<PeerGameDB>>,
    pub tx_notify_ui: tokio::sync::mpsc::UnboundedSender<PeerEvent>,
}

impl std::fmt::Debug for PeerCtx {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("PeerCtx")
            .field("game_dir", &"...")
            .field("local_game_db", &"...")
            .field("local_peer_addr", &"...")
            .field("downloading_games", &"...")
            .finish()
    }
}

impl Ctx {
    /// Creates a new context with the given peer game database.
    pub fn new(peer_game_db: Arc<RwLock<PeerGameDB>>) -> Self {
        Self {
            game_dir: Arc::new(RwLock::new(None)),
            local_game_db: Arc::new(RwLock::new(None)),
            peer_game_db,
            local_peer_addr: Arc::new(RwLock::new(None)),
            downloading_games: Arc::new(RwLock::new(HashSet::new())),
            active_downloads: Arc::new(RwLock::new(HashMap::new())),
        }
    }

    /// Creates a `PeerCtx` from this context.
    pub fn to_peer_ctx(
        &self,
        tx_notify_ui: tokio::sync::mpsc::UnboundedSender<PeerEvent>,
    ) -> PeerCtx {
        PeerCtx {
            game_dir: self.game_dir.clone(),
            local_game_db: self.local_game_db.clone(),
            local_peer_addr: self.local_peer_addr.clone(),
            downloading_games: self.downloading_games.clone(),
            peer_game_db: self.peer_game_db.clone(),
            tx_notify_ui,
        }
    }
}
