use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use tracing::{error, info};

use crate::models::ApiKey;
use crate::repositories::ApiKeyRepository;

/// Cached API key entry.
#[derive(Debug, Clone)]
pub struct CachedKey {
    pub active: bool,
    pub user_id: String,
}

/// Thread-safe in-memory API key cache, periodically refreshed from the database.
#[derive(Clone)]
pub struct ApiKeyCache {
    inner: Arc<RwLock<HashMap<String, CachedKey>>>,
}

impl ApiKeyCache {
    pub fn new() -> Self {
        Self {
            inner: Arc::new(RwLock::new(HashMap::new())),
        }
    }

    /// Look up an API key. Returns `None` if not found.
    pub async fn get(&self, key: &str) -> Option<CachedKey> {
        self.inner.read().await.get(key).cloned()
    }

    /// Refresh the cache from the given repository.
    pub async fn refresh(&self, repo: &impl ApiKeyRepository) {
        match repo.load_all().await {
            Ok(keys) => {
                let count = keys.len();
                let map: HashMap<String, CachedKey> = keys
                    .into_iter()
                    .map(|ApiKey { key, active, user_id }| {
                        (key, CachedKey { active, user_id })
                    })
                    .collect();

                *self.inner.write().await = map;
                info!(count, "refreshed API key cache");
            }
            Err(e) => {
                error!(error = %e, "failed to refresh API key cache");
            }
        }
    }
}
