use chrono::{DateTime, Duration, Utc};
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;

#[derive(Clone, Debug)]
pub struct Session {
    pub username: String,
    pub role: String,
    pub created_at: DateTime<Utc>,
    pub expires_at: DateTime<Utc>,
}

#[derive(Clone)]
pub struct SessionManager {
    sessions: Arc<RwLock<HashMap<String, Session>>>,
    ttl_hours: i64,
}

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

    /// Create a new session and return the session token.
    pub async fn create_session(&self, username: String, role: String) -> String {
        let token = format!("session-{}", uuid::Uuid::new_v4());
        let now = Utc::now();
        let session = Session {
            username,
            role,
            created_at: now,
            expires_at: now + Duration::hours(self.ttl_hours),
        };
        self.sessions.write().await.insert(token.clone(), session);
        token
    }

    /// Validate a session token and return the session if valid and not expired.
    pub async fn validate_session(&self, token: &str) -> Option<Session> {
        let sessions = self.sessions.read().await;
        sessions.get(token).and_then(|s| {
            if s.expires_at > Utc::now() {
                Some(s.clone())
            } else {
                None
            }
        })
    }

    /// Revoke (delete) a session by token.
    pub async fn revoke_session(&self, token: &str) {
        self.sessions.write().await.remove(token);
    }

    /// Remove all expired sessions from the store.
    pub async fn cleanup_expired(&self) {
        let now = Utc::now();
        self.sessions.write().await.retain(|_, s| s.expires_at > now);
    }
}
