use crate::models::card::CardDefinition; use anyhow::{Context, Result}; use std::collections::HashMap; use std::path::Path; /// In-memory card registry loaded from data/cards/*.json pub struct CardDb { pub cards: HashMap, } impl CardDb { pub fn load(data_dir: &str) -> Result { let cards_dir = Path::new(data_dir).join("cards"); let mut cards = HashMap::new(); if !cards_dir.exists() { tracing::warn!("Card data directory not found: {:?}", cards_dir); return Ok(Self { cards }); } for entry in std::fs::read_dir(&cards_dir) .with_context(|| format!("reading cards dir {:?}", cards_dir))? { let entry = entry?; let path = entry.path(); if path.extension().map(|e| e == "json").unwrap_or(false) { let content = std::fs::read_to_string(&path) .with_context(|| format!("reading {:?}", path))?; let batch: Vec = serde_json::from_str(&content) .with_context(|| format!("parsing {:?}", path))?; for card in batch { cards.insert(card.id.clone(), card); } } } tracing::info!("Loaded {} card definitions", cards.len()); Ok(Self { cards }) } pub fn get(&self, id: &str) -> Option<&CardDefinition> { self.cards.get(id) } #[allow(dead_code)] pub fn by_rarity(&self, rarity: &str) -> Vec<&CardDefinition> { self.cards .values() .filter(|c| { let r = format!("{:?}", c.rarity).to_lowercase(); r == rarity || rarity == "any" }) .collect() } pub fn all(&self) -> Vec<&CardDefinition> { self.cards.values().collect() } pub fn by_min_overall(&self, min: u8) -> Vec<&CardDefinition> { self.cards.values().filter(|c| c.overall >= min).collect() } }