//! Cascade session manager — maps session IDs to cascade IDs for reuse.
//!
//! Mimics real webview behavior: one chat tab = one cascade with many messages.
//! Without this, every API call creates a new cascade — an obvious automation
//! fingerprint (100 calls = 100 single-message cascades).

use std::collections::HashMap;
use std::time::Instant;
use tokio::sync::RwLock;

const SESSION_TTL_SECS: u64 = 3600 * 4; // 4 hours

#[derive(Clone)]
struct Session {
    cascade_id: String,
    created: Instant,
    last_used: Instant,
    msg_count: u64,
}

pub struct SessionManager {
    sessions: RwLock<HashMap<String, Session>>,
}

impl SessionManager {
    pub fn new() -> Self {
        Self {
            sessions: RwLock::new(HashMap::new()),
        }
    }

    /// List all active sessions.
    pub async fn list_sessions(&self) -> serde_json::Value {
        let mut sessions = self.sessions.write().await;
        cleanup_expired(&mut sessions);

        let now = Instant::now();
        let mut map = serde_json::Map::new();
        for (sid, sess) in sessions.iter() {
            map.insert(
                sid.clone(),
                serde_json::json!({
                    "cascade_id": sess.cascade_id,
                    "msg_count": sess.msg_count,
                    "age_seconds": now.duration_since(sess.created).as_secs(),
                    "idle_seconds": now.duration_since(sess.last_used).as_secs(),
                }),
            );
        }
        serde_json::Value::Object(map)
    }

    /// Delete a session. Returns true if it existed.
    pub async fn delete_session(&self, session_id: &str) -> bool {
        let mut sessions = self.sessions.write().await;
        sessions.remove(session_id).is_some()
    }
}

fn cleanup_expired(sessions: &mut HashMap<String, Session>) {
    let now = Instant::now();
    sessions.retain(|_, s| now.duration_since(s.last_used).as_secs() < SESSION_TTL_SECS);
}
