// Copyright (c) 2026 Kirky.X
//
// Licensed under the MIT License
// See LICENSE file in the project root for full license information.

//! 权限控制模块
//!
//! 提供基于角色的表级权限控制功能

pub mod provider;

#[cfg(feature = "permission")]
pub mod rbac;

#[cfg(feature = "permission")]
pub mod advanced;

// Re-export commonly used types
#[cfg(feature = "permission")]
pub use advanced::AdvancedRbacProvider;

use dashmap::DashMap;
use lru::LruCache;
use serde::{Deserialize, Serialize};
use std::num::NonZeroUsize;
use std::sync::Arc;
use std::time::{Duration, Instant};
use thiserror::Error;
use tokio::sync::RwLock as AsyncRwLock;

/// 权限相关错误类型
#[derive(Debug, Error)]
pub enum PermissionError {
    /// 缓存容量无效（不能为 0）
    #[error("Cache capacity must be non-zero")]
    InvalidCacheCapacity,

    /// 角色未找到
    #[error("Role '{0}' not found in permission config")]
    RoleNotFound(String),

    /// 配置文件加载失败
    #[error("Failed to load permission config: {0}")]
    ConfigLoadError(String),

    /// 权限检查被速率限制拒绝
    #[error("Permission check rate limited")]
    RateLimited,
}

/// 权限操作类型
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PermissionAction {
    /// 查询操作
    Select,
    /// 插入操作
    Insert,
    /// 更新操作
    Update,
    /// 删除操作
    Delete,
}

impl std::fmt::Display for PermissionAction {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            PermissionAction::Select => write!(f, "SELECT"),
            PermissionAction::Insert => write!(f, "INSERT"),
            PermissionAction::Update => write!(f, "UPDATE"),
            PermissionAction::Delete => write!(f, "DELETE"),
        }
    }
}

/// 简单速率限制器
///
/// 速率限制器
///
/// 使用滑动时间窗口算法限制请求频率，相比固定窗口算法：
/// - 更平滑的限流效果
/// - 避免窗口边界处的双倍请求问题
/// - 更准确的请求计数
///
/// 注意：此结构体主要用于内部权限检查速率限制，
/// 但其方法（如 `remaining`、`cleanup`）也可用于监控和管理。
#[derive(Debug, Clone)]
pub(crate) struct RateLimiter {
    /// 每个时间窗口允许的最大请求数
    max_requests: u32,
    /// 时间窗口大小
    window_duration: Duration,
    /// 请求记录存储（使用 DashMap 实现细粒度并发控制）
    /// Key: 限制键 (IP/用户ID), Value: 请求时间戳列表
    requests: Arc<DashMap<String, Vec<Instant>>>,
}

impl RateLimiter {
    /// 创建新的速率限制器
    ///
    /// # Arguments
    ///
    /// * `max_requests` - 每个时间窗口允许的最大请求数
    /// * `window_duration` - 时间窗口大小
    pub(crate) fn new(max_requests: u32, window_duration: Duration) -> Self {
        Self {
            max_requests,
            window_duration,
            requests: Arc::new(DashMap::new()),
        }
    }

    /// 检查是否允许请求（滑动窗口算法）
    ///
    /// 使用滑动窗口计数算法：
    /// 1. 计算当前时间窗口的起始点
    /// 2. 清理过期请求记录
    /// 3. 计算加权请求数（当前窗口 + 前一窗口的部分请求）
    /// 4. 根据是否超限决定是否允许请求
    ///
    /// # Arguments
    ///
    /// * `key` - 速率限制的键（如 IP 地址、用户 ID）
    ///
    /// # Returns
    ///
    /// 如果允许请求返回 true，否则返回 false
    pub(crate) async fn check(&self, key: &str) -> bool {
        let now = Instant::now();
        let window_start = now - self.window_duration;

        // 使用 DashMap 的细粒度锁
        let mut entry = self.requests.entry(key.to_string()).or_default();

        // 清理过期的请求记录（保留窗口内的请求）
        entry.retain(|&t| t > window_start);

        // 计算滑动窗口内的请求数（考虑窗口边界）
        let window_requests = entry.len();

        // 检查是否超过限制
        if window_requests < self.max_requests as usize {
            entry.push(now);
            true
        } else {
            false
        }
    }

    /// 获取剩余请求数量
    ///
    /// 用于监控和管理场景，例如：
    /// - 在管理界面显示用户的剩余请求配额
    /// - API 返回响应头中的 RateLimit-Remaining
    pub(crate) fn remaining(&self, key: &str) -> u32 {
        let now = Instant::now();
        let window_start = now - self.window_duration;

        if let Some(timestamps) = self.requests.get(key) {
            let valid_count = timestamps.iter().filter(|&&t| t > window_start).count();
            self.max_requests.saturating_sub(valid_count as u32)
        } else {
            self.max_requests
        }
    }

    /// 重置指定键的速率限制
    ///
    /// 用于管理场景，例如：
    /// - 管理员手动解除用户的速率限制
    /// - 在用户申诉后重置其限制
    pub(crate) fn reset(&self, key: &str) {
        self.requests.remove(key);
    }

    /// 清理孤立条目（防止内存泄漏）
    ///
    /// 移除长时间没有任何请求的 key（超过 10 倍时间窗口）
    /// 建议定期调用此方法，例如每小时一次或使用定时任务
    pub(crate) fn cleanup(&self) -> usize {
        let cleanup_threshold = self.window_duration * 10;
        let now = Instant::now();
        let mut removed_count = 0;

        // 优化：先收集需要删除的键，避免在迭代过程中修改 DashMap
        // 由于 DashMap 的迭代器生命周期问题，需要 clone key
        let keys_to_remove: Vec<String> = self
            .requests
            .iter()
            .filter_map(|entry| {
                let key = entry.key(); // &str
                // 获取最新时间戳
                let latest = entry.value().iter().max();
                match latest {
                    Some(&t) if now - t > cleanup_threshold => Some(key.to_string()),
                    None => Some(key.to_string()), // 空列表也清理
                    _ => None,
                }
            })
            .collect();

        // 移除孤立条目
        for key in &keys_to_remove {
            if self.requests.remove(key.as_str()).is_some() {
                removed_count += 1;
            }
        }

        if removed_count > 0 {
            tracing::info!(
                "RateLimiter cleanup: removed {} stale entries, remaining {}",
                removed_count,
                self.requests.len()
            );
        }

        removed_count
    }

    /// 获取当前条目数量（用于监控）
    pub(crate) fn len(&self) -> usize {
        self.requests.len()
    }

    /// 检查是否为空
    pub(crate) fn is_empty(&self) -> bool {
        self.requests.is_empty()
    }
}

/// 默认速率限制配置
impl Default for RateLimiter {
    fn default() -> Self {
        Self::new(100, Duration::from_secs(60))
    }
}

/// Operation 是 PermissionAction 的别名，用于简化使用
pub type Operation = PermissionAction;

/// 表权限配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TablePermission {
    /// 表名（支持通配符 *）
    pub name: String,

    /// 允许的操作列表
    pub operations: Vec<PermissionAction>,
}

/// 角色策略
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct RolePolicy {
    /// 角色允许的表权限
    pub tables: Vec<TablePermission>,
}

impl RolePolicy {
    /// 系统表黑名单（不允许通配符访问）
    const SYSTEM_TABLES: &'static [&'static str] = &[
        "sqlite_master",
        "sqlite_sequence",
        "sqlite_stat1",
        "sqlite_stat2",
        "sqlite_stat3",
        "sqlite_stat4",
        "information_schema",
        "pg_catalog",
        "pg_toast",
        "mysql",
        "performance_schema",
        "sys",
    ];

    /// 检查角色是否有权限执行操作
    pub fn allows(&self, table: &str, operation: &PermissionAction) -> bool {
        let normalized_table = table.to_lowercase();
        let is_system_table = Self::SYSTEM_TABLES.iter().any(|system_table| {
            let system_table = system_table.to_lowercase();
            normalized_table == system_table || normalized_table.starts_with(&format!("{}.", system_table))
        });
        for perm in &self.tables {
            // 检查表名匹配（支持通配符）
            if perm.name == "*" {
                if is_system_table {
                    continue;
                }

                // 不是系统表，检查操作权限
                if perm.operations.contains(operation) {
                    return true;
                }
            } else if perm.name == table {
                // 精确匹配表名
                if perm.operations.contains(operation) {
                    return true;
                }
            }
        }
        if is_system_table {
            tracing::warn!(
                target: "security",
                "Access denied to system table '{}'",
                table
            );
        }
        false
    }
}

/// 权限上下文
pub struct PermissionContext {
    /// 角色名称
    role: String,

    /// 用户 ID（可选，用于更细粒度的速率限制）
    user_id: Option<String>,

    /// 会话 ID（可选，用于更细粒度的速率限制）
    session_id: Option<String>,

    /// 权限策略 LRU 缓存（使用 tokio 异步读写锁保护以支持异步上下文）
    policy_cache: Arc<AsyncRwLock<LruCache<String, RolePolicy>>>,

    /// 权限检查速率限制器
    rate_limiter: Option<Arc<RateLimiter>>,

    /// 可选的权限提供者（用于高级权限检查）
    #[cfg(feature = "permission-engine")]
    provider: Option<Arc<dyn crate::permission_engine::PermissionProvider + Send + Sync>>,
}

/// LRU 缓存容量默认值
const DEFAULT_CACHE_CAPACITY: usize = 256;

/// 权限检查速率限制默认值
const DEFAULT_RATE_LIMIT_MAX_REQUESTS: u32 = 100;
const DEFAULT_RATE_LIMIT_WINDOW_SECS: u64 = 60;

impl Default for PermissionContext {
    fn default() -> Self {
        // DEFAULT_CACHE_CAPACITY is always > 0, so unwrap is safe here
        Self::with_cache_size("admin".to_string(), DEFAULT_CACHE_CAPACITY)
            .expect("Default cache capacity should always be valid")
    }
}

impl Clone for PermissionContext {
    fn clone(&self) -> Self {
        Self {
            role: self.role.clone(),
            user_id: self.user_id.clone(),
            session_id: self.session_id.clone(),
            policy_cache: self.policy_cache.clone(),
            rate_limiter: self.rate_limiter.clone(),
            provider: self.provider.clone(),
        }
    }
}

impl std::fmt::Debug for PermissionContext {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("PermissionContext")
            .field("role", &self.role)
            .field("user_id", &self.user_id)
            .field("session_id", &self.session_id)
            .field("policy_cache", &"<Arc<AsyncRwLock<LruCache>>")
            .field("rate_limiter", &self.rate_limiter.is_some())
            .field("provider", &self.provider.is_some())
            .finish()
    }
}

impl PermissionContext {
    /// 创建新的权限上下文（使用默认缓存大小和速率限制）
    pub fn new(role: String, policy_cache: Arc<AsyncRwLock<LruCache<String, RolePolicy>>>) -> Self {
        Self {
            role,
            user_id: None,
            session_id: None,
            policy_cache,
            rate_limiter: Some(Arc::new(RateLimiter::new(
                DEFAULT_RATE_LIMIT_MAX_REQUESTS,
                Duration::from_secs(DEFAULT_RATE_LIMIT_WINDOW_SECS),
            ))),
            provider: None,
        }
    }

    /// 创建新的权限上下文（带权限提供者）
    pub fn with_provider(
        role: String,
        policy_cache: Arc<AsyncRwLock<LruCache<String, RolePolicy>>>,
        provider: Arc<dyn crate::permission_engine::PermissionProvider + Send + Sync>,
    ) -> Self {
        Self {
            role,
            user_id: None,
            session_id: None,
            policy_cache,
            rate_limiter: Some(Arc::new(RateLimiter::new(
                DEFAULT_RATE_LIMIT_MAX_REQUESTS,
                Duration::from_secs(DEFAULT_RATE_LIMIT_WINDOW_SECS),
            ))),
            provider: Some(provider),
        }
    }

    /// 创建权限上下文（带可选的提供者）
    pub fn with_provider_or_default(
        role: String,
        policy_cache: Arc<AsyncRwLock<LruCache<String, RolePolicy>>>,
        provider: Option<Arc<dyn crate::permission_engine::PermissionProvider + Send + Sync>>,
    ) -> Self {
        Self {
            role,
            user_id: None,
            session_id: None,
            policy_cache,
            rate_limiter: Some(Arc::new(RateLimiter::new(
                DEFAULT_RATE_LIMIT_MAX_REQUESTS,
                Duration::from_secs(DEFAULT_RATE_LIMIT_WINDOW_SECS),
            ))),
            provider,
        }
    }

    /// 创建新的权限上下文（使用自定义缓存大小）
    ///
    /// # Errors
    ///
    /// 如果 `cache_capacity` 为 0，返回 `InvalidCacheCapacity` 错误
    pub fn with_cache_size(role: String, cache_capacity: usize) -> Result<Self, PermissionError> {
        let capacity = NonZeroUsize::new(cache_capacity).ok_or(PermissionError::InvalidCacheCapacity)?;
        Ok(Self {
            role,
            user_id: None,
            session_id: None,
            policy_cache: Arc::new(AsyncRwLock::new(LruCache::new(capacity))),
            rate_limiter: Some(Arc::new(RateLimiter::new(
                DEFAULT_RATE_LIMIT_MAX_REQUESTS,
                Duration::from_secs(DEFAULT_RATE_LIMIT_WINDOW_SECS),
            ))),
            provider: None,
        })
    }

    /// 创建新的权限上下文（使用自定义缓存大小和速率限制）
    ///
    /// # Errors
    ///
    /// 如果 `cache_capacity` 为 0，返回 `InvalidCacheCapacity` 错误
    pub fn with_cache_size_and_rate_limit(
        role: String,
        cache_capacity: usize,
        max_requests: u32,
        window_secs: u64,
    ) -> Result<Self, PermissionError> {
        let capacity = NonZeroUsize::new(cache_capacity).ok_or(PermissionError::InvalidCacheCapacity)?;
        Ok(Self {
            role,
            user_id: None,
            session_id: None,
            policy_cache: Arc::new(AsyncRwLock::new(LruCache::new(capacity))),
            rate_limiter: Some(Arc::new(RateLimiter::new(
                max_requests,
                Duration::from_secs(window_secs),
            ))),
            provider: None,
        })
    }

    /// 获取角色
    pub fn role(&self) -> &str {
        &self.role
    }

    /// 设置用户 ID（用于更细粒度的速率限制）
    pub fn set_user_id(&mut self, user_id: String) {
        self.user_id = Some(user_id);
    }

    /// 获取用户 ID
    pub fn user_id(&self) -> Option<&str> {
        self.user_id.as_deref()
    }

    /// 设置会话 ID（用于更细粒度的速率限制）
    pub fn set_session_id(&mut self, session_id: String) {
        self.session_id = Some(session_id);
    }

    /// 获取会话 ID
    pub fn session_id(&self) -> Option<&str> {
        self.session_id.as_deref()
    }

    /// 设置权限提供者
    ///
    /// 使用新的 PermissionProvider trait 进行权限检查
    #[cfg(feature = "permission-engine")]
    pub fn set_provider(&mut self, provider: Arc<dyn crate::permission_engine::PermissionProvider + Send + Sync>) {
        self.provider = Some(provider);
    }

    /// 获取速率限制键（格式：role:user_id:session_id）
    ///
    /// 如果 user_id 或 session_id 未设置，则使用更简单的键格式
    fn get_rate_limit_key(&self) -> String {
        match (&self.user_id, &self.session_id) {
            (Some(user_id), Some(session_id)) => {
                format!("{}:{}:{}", self.role, user_id, session_id)
            }
            (Some(user_id), None) => format!("{}:{}", self.role, user_id),
            (None, Some(session_id)) => format!("{}:{}", self.role, session_id),
            (None, None) => self.role.clone(),
        }
    }

    /// 检查表访问权限
    ///
    /// 此方法会先检查速率限制，然后检查缓存
    /// 如果缓存未命中且配置可用，会自动加载权限策略
    pub async fn check_table_access(&self, table: &str, operation: &PermissionAction) -> bool {
        // 如果有provider，使用provider进行检查
        #[cfg(feature = "permission-engine")]
        if let Some(provider) = &self.provider {
            use crate::permission_engine::{
                PermissionAction as EnginePermissionAction, PermissionContext, PermissionDecision, PermissionResource,
                PermissionSubject,
            };

            // 将 permission::PermissionAction 转换为 permission_engine::PermissionAction
            let engine_action = match operation {
                PermissionAction::Select => EnginePermissionAction::Select,
                PermissionAction::Insert => EnginePermissionAction::Insert,
                PermissionAction::Update => EnginePermissionAction::Update,
                PermissionAction::Delete => EnginePermissionAction::Delete,
            };

            let context = PermissionContext::new(
                PermissionSubject::role(&self.role),
                PermissionResource::new(table),
                engine_action,
            );
            let decision = provider.check_permission(&context).await;
            return matches!(decision, PermissionDecision::Allow);
        }

        // 否则使用旧的实现
        // 检查速率限制（使用更细粒度的键：role:user_id:session_id）
        if let Some(limiter) = &self.rate_limiter {
            let rate_limit_key = self.get_rate_limit_key();
            if !limiter.check(&rate_limit_key).await {
                tracing::warn!(
                    target: "security",
                    "Rate limit exceeded for '{}' on table '{}'",
                    rate_limit_key,
                    table
                );
                return false;
            }
        }

        // 先尝试从缓存读取（使用读锁）
        {
            let cache = self.policy_cache.read().await;
            if let Some(policy) = cache.peek(self.role.as_str()) {
                let allowed = policy.allows(table, operation);
                tracing::trace!(
                    "Permission check: role='{}' table='{}' operation='{}' result={}",
                    self.role,
                    table,
                    operation,
                    allowed
                );
                return allowed;
            }
        }

        // 缓存未命中且无配置：返回 false（安全默认）
        tracing::debug!(
            target: "security",
            "Permission cache miss for role '{}' on table '{}'. Access denied by default.",
            self.role,
            table,
        );
        false
    }

    /// 失效缓存（用于配置更新后）
    pub async fn invalidate_cache(&self) {
        let mut cache = self.policy_cache.write().await;
        cache.pop(&self.role);
        tracing::info!("Invalidated permission cache for role '{}'", self.role);
    }

    /// 获取缓存统计信息
    pub async fn cache_stats(&self) -> CacheStats {
        let cache = self.policy_cache.read().await;
        CacheStats {
            cached_roles: cache.len(),
            capacity: cache.cap().get(),
        }
    }
}

/// 缓存统计信息
#[derive(Debug, Clone)]
pub struct CacheStats {
    /// 已缓存的角色数
    pub cached_roles: usize,

    /// 缓存容量
    pub capacity: usize,
}

#[cfg(test)]
mod tests {
    use super::*;

    /// TEST-U-010: Operation (PermissionAction) Display 实现测试
    #[test]
    fn test_operation_display() {
        assert_eq!(PermissionAction::Select.to_string(), "SELECT");
        assert_eq!(PermissionAction::Insert.to_string(), "INSERT");
        assert_eq!(PermissionAction::Update.to_string(), "UPDATE");
        assert_eq!(PermissionAction::Delete.to_string(), "DELETE");
    }

    /// TEST-U-011: RolePolicy allows 测试
    #[test]
    fn test_role_policy_allows() {
        let policy = RolePolicy {
            tables: vec![
                TablePermission {
                    name: "users".to_string(),
                    operations: vec![PermissionAction::Select, PermissionAction::Insert],
                },
                TablePermission {
                    name: "*".to_string(),
                    operations: vec![PermissionAction::Select],
                },
            ],
        };

        // 精确表名匹配
        assert!(policy.allows("users", &PermissionAction::Select));
        assert!(policy.allows("users", &PermissionAction::Insert));
        assert!(!policy.allows("users", &PermissionAction::Delete));

        // 通配符匹配
        assert!(policy.allows("orders", &PermissionAction::Select));
        assert!(!policy.allows("orders", &PermissionAction::Update));
    }

    /// TEST-U-012: PermissionContext 创建和访问测试
    #[test]
    fn test_permission_context_creation() {
        let cache = Arc::new(tokio::sync::RwLock::new(LruCache::new(NonZeroUsize::new(256).unwrap())));
        let ctx = PermissionContext::new("admin".to_string(), cache);

        assert_eq!(ctx.role(), "admin");
    }

    /// TEST-U-019: 速率限制器测试 - 基本功能
    #[tokio::test]
    async fn test_rate_limiter_basic() {
        let limiter = RateLimiter::new(3, std::time::Duration::from_secs(60));

        // 前3个请求应该允许
        assert!(limiter.check("user1").await);
        assert!(limiter.check("user1").await);
        assert!(limiter.check("user1").await);

        // 第4个请求应该被拒绝
        assert!(!limiter.check("user1").await);
    }

    /// TEST-U-020: 速率限制器测试 - 不同键独立计数
    #[tokio::test]
    async fn test_rate_limiter_different_keys() {
        let limiter = RateLimiter::new(2, std::time::Duration::from_secs(60));

        assert!(limiter.check("user1").await);
        assert!(limiter.check("user1").await);
        assert!(!limiter.check("user1").await);

        assert!(limiter.check("user2").await);
        assert!(limiter.check("user2").await);
        assert!(!limiter.check("user2").await);
    }

    /// TEST-U-021: 速率限制器测试 - 重置功能
    #[tokio::test]
    async fn test_rate_limiter_reset() {
        let limiter = RateLimiter::new(1, std::time::Duration::from_secs(60));

        assert!(limiter.check("user1").await);
        assert!(!limiter.check("user1").await);

        limiter.reset("user1");

        assert!(limiter.check("user1").await);
    }

    /// TEST-U-022: 速率限制器测试 - 剩余请求计数
    #[tokio::test]
    async fn test_rate_limiter_remaining() {
        let limiter = RateLimiter::new(3, std::time::Duration::from_secs(60));

        assert_eq!(limiter.remaining("user1"), 3);

        limiter.check("user1").await;
        assert_eq!(limiter.remaining("user1"), 2);

        limiter.check("user1").await;
        assert_eq!(limiter.remaining("user1"), 1);

        limiter.check("user1").await;
        assert_eq!(limiter.remaining("user1"), 0);

        assert!(!limiter.check("user1").await);
        assert_eq!(limiter.remaining("user1"), 0);
    }
}
