use dashmap::DashMap;
use tokio::sync::{mpsc, oneshot};
use uuid::Uuid;
use serde::Serialize;
use helios_common::protocol::{ClientMessage, ServerMessage};

/// Represents one connected remote client.
/// The device label is the sole identifier — no session UUIDs exposed externally.
#[derive(Debug, Clone)]
pub struct Session {
    pub label: String,
    /// Channel to send commands to the WS handler for this session
    pub cmd_tx: mpsc::Sender<ServerMessage>,
}

/// Serializable view of a session for the REST API
#[derive(Debug, Serialize)]
pub struct SessionInfo {
    pub label: String,
}

impl From<&Session> for SessionInfo {
    fn from(s: &Session) -> Self {
        SessionInfo {
            label: s.label.clone(),
        }
    }
}

pub struct SessionStore {
    /// Active sessions keyed by device label
    sessions: DashMap<String, Session>,
    /// Pending request callbacks by request_id
    pending: DashMap<Uuid, oneshot::Sender<ClientMessage>>,
}

impl SessionStore {
    pub fn new() -> Self {
        Self {
            sessions: DashMap::new(),
            pending: DashMap::new(),
        }
    }

    pub fn insert(&self, session: Session) {
        self.sessions.insert(session.label.clone(), session);
    }

    pub fn remove(&self, label: &str) {
        self.sessions.remove(label);
    }

    pub fn get_cmd_tx(&self, label: &str) -> Option<mpsc::Sender<ServerMessage>> {
        self.sessions.get(label).map(|s| s.cmd_tx.clone())
    }

    pub fn list(&self) -> Vec<SessionInfo> {
        self.sessions.iter().map(|e| SessionInfo::from(e.value())).collect()
    }

    /// Register a pending request. Returns the receiver to await the client response.
    pub fn register_pending(&self, request_id: Uuid) -> oneshot::Receiver<ClientMessage> {
        let (tx, rx) = oneshot::channel();
        self.pending.insert(request_id, tx);
        rx
    }

    /// Deliver a client response to the waiting request handler.
    pub fn resolve_pending(&self, request_id: Uuid, msg: ClientMessage) -> bool {
        if let Some((_, tx)) = self.pending.remove(&request_id) {
            let _ = tx.send(msg);
            true
        } else {
            false
        }
    }
}
