use anyhow::Result;
use notify::{Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher};
use std::path::{Path, PathBuf};
use tokio::sync::mpsc;
use tracing::debug;

pub enum WatchEvent {
    Changed(PathBuf),
    Removed(PathBuf),
}

/// Start a single notify watcher for one or more paths. All events route to the same channel.
pub fn start_many(paths: &[PathBuf]) -> Result<(RecommendedWatcher, mpsc::Receiver<WatchEvent>)> {
    let (tx, rx) = mpsc::channel::<WatchEvent>(128);

    let mut watcher = notify::recommended_watcher(move |res: notify::Result<Event>| {
        let Ok(event) = res else { return };
        let kind = event.kind;
        for path in event.paths {
            if path.extension().is_none_or(|e| e != "ncl") {
                continue;
            }
            let evt = match &kind {
                EventKind::Remove(_) => WatchEvent::Removed(path),
                _ => WatchEvent::Changed(path),
            };
            let _ = tx.try_send(evt);
        }
    })?;

    for p in paths {
        if p.exists() {
            watcher.watch(p, RecursiveMode::Recursive)?;
            debug!("watching: {}", p.display());
        } else {
            debug!("skip watch (not found): {}", p.display());
        }
    }

    Ok((watcher, rx))
}

/// Convenience wrapper for single-path watching (preserves old API for tests/tools).
#[allow(dead_code)]
pub fn start(watch_path: &Path) -> Result<(RecommendedWatcher, mpsc::Receiver<WatchEvent>)> {
    start_many(&[watch_path.to_path_buf()])
}
