#![deny(warnings)]
#![allow(dead_code)]
//! [TSM.ID].[11031972] -- Platform X Ecosystem
//! xcu-iam-gatekeeper -- Identity Access Management Gateway
//! JWT validation, RBAC, session management, rate limiting per user

use std::collections::HashMap;
use std::sync::{Arc, Mutex};

#[derive(Debug)]
pub enum GatekeeperError { Unauthorized(String), Forbidden(String), SessionExpired(String), RateLimited(String) }
impl std::fmt::Display for GatekeeperError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self { Self::Unauthorized(e) => write!(f, "Unauthorized: {e}"), Self::Forbidden(e) => write!(f, "Forbidden: {e}"), Self::SessionExpired(e) => write!(f, "Expired: {e}"), Self::RateLimited(e) => write!(f, "Rate limited: {e}") }
    }
}
impl std::error::Error for GatekeeperError {}

#[derive(Debug, Clone, PartialEq)]
pub enum Role { Admin, Moderator, User, Guest, Service }
impl Role {
    pub fn level(&self) -> u8 { match self { Self::Admin => 100, Self::Moderator => 50, Self::User => 20, Self::Guest => 5, Self::Service => 80 } }
}

#[derive(Debug, Clone)]
pub struct Session { pub user_id: String, pub role: Role, pub created_at: u64, pub expires_at: u64, pub ip_addr: String, pub device_fingerprint: String }

#[derive(Debug, Clone)]
pub struct Permission { pub resource: String, pub action: String, pub min_role_level: u8 }

struct RateState { count: u32, window_start: u64 }

pub struct Gatekeeper {
    sessions: Arc<Mutex<HashMap<String, Session>>>,
    permissions: Vec<Permission>,
    rate_limits: Arc<Mutex<HashMap<String, RateState>>>,
    max_requests_per_minute: u32,
}

impl Gatekeeper {
    pub fn new(max_rpm: u32) -> Self {
        Self { sessions: Arc::new(Mutex::new(HashMap::new())), permissions: Vec::new(), rate_limits: Arc::new(Mutex::new(HashMap::new())), max_requests_per_minute: max_rpm }
    }

    pub fn add_permission(&mut self, perm: Permission) { self.permissions.push(perm); }

    pub fn create_session(&self, token: &str, session: Session) -> Result<(), GatekeeperError> {
        if let Ok(mut sessions) = self.sessions.lock() { sessions.insert(token.into(), session); Ok(()) }
        else { Err(GatekeeperError::Unauthorized("Lock failed".into())) }
    }

    pub fn validate_session(&self, token: &str, now: u64) -> Result<Session, GatekeeperError> {
        let sessions = self.sessions.lock().map_err(|_| GatekeeperError::Unauthorized("Lock".into()))?;
        let session = sessions.get(token).ok_or_else(|| GatekeeperError::Unauthorized("Invalid token".into()))?;
        if now > session.expires_at { return Err(GatekeeperError::SessionExpired(format!("Expired {}s ago", now - session.expires_at))); }
        Ok(session.clone())
    }

    pub fn check_permission(&self, role: &Role, resource: &str, action: &str) -> Result<bool, GatekeeperError> {
        for perm in &self.permissions {
            if perm.resource == resource && perm.action == action {
                if role.level() >= perm.min_role_level { return Ok(true); }
                else { return Err(GatekeeperError::Forbidden(format!("{:?} level {} < required {}", role, role.level(), perm.min_role_level))); }
            }
        }
        Ok(false) // No matching permission = deny
    }

    pub fn check_rate_limit(&self, user_id: &str, now: u64) -> Result<u32, GatekeeperError> {
        let mut limits = self.rate_limits.lock().map_err(|_| GatekeeperError::RateLimited("Lock".into()))?;
        let state = limits.entry(user_id.into()).or_insert(RateState { count: 0, window_start: now });
        if now - state.window_start >= 60 { state.count = 0; state.window_start = now; }
        state.count += 1;
        if state.count > self.max_requests_per_minute {
            Err(GatekeeperError::RateLimited(format!("{} requests/min > {}", state.count, self.max_requests_per_minute)))
        } else { Ok(self.max_requests_per_minute - state.count) }
    }

    /// Full auth pipeline: validate → check permission → check rate limit
    pub fn authorize(&self, token: &str, resource: &str, action: &str, now: u64) -> Result<Session, GatekeeperError> {
        let session = self.validate_session(token, now)?;
        self.check_permission(&session.role, resource, action)?;
        self.check_rate_limit(&session.user_id, now)?;
        Ok(session)
    }

    pub fn revoke_session(&self, token: &str) -> bool {
        self.sessions.lock().map(|mut s| s.remove(token).is_some()).unwrap_or(false)
    }

    pub fn active_sessions(&self) -> usize { self.sessions.lock().map(|s| s.len()).unwrap_or(0) }
}

#[cfg(test)]
mod tests {
    use super::*;
    fn setup() -> Gatekeeper {
        let mut gk = Gatekeeper::new(60);
        gk.add_permission(Permission { resource: "chat".into(), action: "send".into(), min_role_level: 20 });
        gk.add_permission(Permission { resource: "admin".into(), action: "delete".into(), min_role_level: 100 });
        gk.create_session("tok-1", Session { user_id: "u1".into(), role: Role::User, created_at: 1000, expires_at: 9999, ip_addr: "1.2.3.4".into(), device_fingerprint: "abc".into() }).unwrap();
        gk
    }
    #[test]
    fn test_auth_ok() { let gk = setup(); assert!(gk.authorize("tok-1", "chat", "send", 2000).is_ok()); }
    #[test]
    fn test_auth_forbidden() { let gk = setup(); assert!(gk.authorize("tok-1", "admin", "delete", 2000).is_err()); }
    #[test]
    fn test_expired() { let gk = setup(); assert!(gk.validate_session("tok-1", 99999).is_err()); }
    #[test]
    fn test_rate_limit() {
        let gk = setup();
        for _ in 0..60 { gk.check_rate_limit("u1", 1000).unwrap(); }
        assert!(gk.check_rate_limit("u1", 1000).is_err());
    }
}
