//! Filesystem watcher for the open vault.
//!
//! The vault is shared with Obsidian, Tolaria and Git, so notes change under us.
//! A single recursive watcher per process is enough: the renderer debounces the
//! resulting events and reloads what it needs.

use std::path::Path;
use std::sync::Mutex;

use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use tauri::{AppHandle, Emitter};

pub struct VaultWatcher {
    watcher: Mutex<Option<RecommendedWatcher>>,
}

impl VaultWatcher {
    pub fn new() -> Self {
        Self {
            watcher: Mutex::new(None),
        }
    }

    /// Watch `root`, replacing any previous watch.
    pub fn watch(&self, app: AppHandle, root: &str) -> Result<(), String> {
        let mut slot = self.watcher.lock().map_err(|error| error.to_string())?;
        *slot = None;

        let mut watcher = notify::recommended_watcher(move |result: notify::Result<notify::Event>| {
            let Ok(event) = result else { return };
            let paths: Vec<String> = event
                .paths
                .iter()
                .map(|path| path.to_string_lossy().to_string())
                .collect();
            if paths.is_empty() {
                return;
            }
            let _ = app.emit("vault-changed", paths);
        })
        .map_err(|error| error.to_string())?;

        watcher
            .watch(Path::new(root), RecursiveMode::Recursive)
            .map_err(|error| format!("无法监听 {root}: {error}"))?;
        *slot = Some(watcher);
        Ok(())
    }
}

impl Default for VaultWatcher {
    fn default() -> Self {
        Self::new()
    }
}