use std::collections::{HashMap, HashSet};
use std::path::{Path, PathBuf};
use std::sync::{LazyLock, Mutex};
use std::time::SystemTime;
use crate::calendar::calendar_event::CalendarEvent;
use crate::error::CalDirResult;
struct CacheEntry {
mtime: Option<SystemTime>,
event: Option<CalendarEvent>,
}
type DirCache = HashMap<PathBuf, CacheEntry>;
static CACHE: LazyLock<Mutex<HashMap<PathBuf, DirCache>>> =
LazyLock::new(|| Mutex::new(HashMap::new()));
pub(super) fn cached_events_for_dir(dir: &Path) -> CalDirResult<Vec<CalendarEvent>> {
let mut entries: Vec<(PathBuf, Option<SystemTime>)> = Vec::new();
for entry in std::fs::read_dir(dir)? {
let Ok(entry) = entry else { continue };
let path = entry.path();
if path.extension().is_none_or(|e| e != "ics") {
continue;
}
let mtime = entry.metadata().ok().and_then(|m| m.modified().ok());
entries.push((path, mtime));
}
let mut cache = CACHE.lock().unwrap();
let dir_cache = cache.entry(dir.to_path_buf()).or_default();
let mut events = Vec::with_capacity(entries.len());
let mut present: HashSet<PathBuf> = HashSet::with_capacity(entries.len());
for (path, mtime) in entries {
present.insert(path.clone());
let needs_parse = match dir_cache.get(&path) {
Some(entry) => entry.mtime != mtime,
None => true,
};
if needs_parse {
let event = CalendarEvent::from_file(path.clone()).ok();
if let Some(ref e) = event {
events.push(e.clone());
}
dir_cache.insert(path, CacheEntry { mtime, event });
} else if let Some(entry) = dir_cache.get(&path)
&& let Some(event) = &entry.event
{
events.push(event.clone());
}
}
dir_cache.retain(|p, _| present.contains(p));
Ok(events)
}