use anyhow::Result;

use astmap_core::model::WhyResult;
use astmap_core::QueryStore;

use super::resolve_symbol_id;

pub fn why_path(db: &dyn QueryStore, from: &str, to: &str, depth: i64) -> Result<WhyResult> {
    let from_id = resolve_symbol_id(db, from)?;
    let to_id = resolve_symbol_id(db, to)?;
    let path = db.find_path(from_id, to_id, depth)?;
    Ok(WhyResult {
        from_name: from.to_string(),
        to_name: to.to_string(),
        path,
    })
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::infra::discovery::IgnoreWalkDiscovery;
    use astmap_languages::DefaultLanguageRegistry;
    use std::fs;

    fn setup_db(dir: &std::path::Path) -> Box<dyn QueryStore> {
        let db = crate::infra::sqlite::open(dir).unwrap();
        astmap_core::scanner::scan(
            dir,
            db.as_ref(),
            true,
            &DefaultLanguageRegistry,
            &IgnoreWalkDiscovery,
        )
        .unwrap();
        db
    }

    #[test]
    fn finds_direct_path() {
        let dir = tempfile::tempdir().unwrap();
        let src = dir.path().join("src");
        fs::create_dir_all(&src).unwrap();
        fs::write(
            src.join("main.rs"),
            "fn main() { helper(); }\nfn helper() {}",
        )
        .unwrap();

        let db = setup_db(dir.path());
        let result = why_path(db.as_ref(), "main", "helper", 5).unwrap();
        assert_eq!(result.from_name, "main");
        assert_eq!(result.to_name, "helper");
    }

    #[test]
    fn from_not_found() {
        let dir = tempfile::tempdir().unwrap();
        let src = dir.path().join("src");
        fs::create_dir_all(&src).unwrap();
        fs::write(src.join("lib.rs"), "pub fn hello() {}").unwrap();

        let db = setup_db(dir.path());
        assert!(why_path(db.as_ref(), "nonexistent", "hello", 5).is_err());
    }

    #[test]
    fn to_not_found() {
        let dir = tempfile::tempdir().unwrap();
        let src = dir.path().join("src");
        fs::create_dir_all(&src).unwrap();
        fs::write(src.join("lib.rs"), "pub fn hello() {}").unwrap();

        let db = setup_db(dir.path());
        assert!(why_path(db.as_ref(), "hello", "nonexistent", 5).is_err());
    }

    #[test]
    fn no_connection_returns_empty_path() {
        let dir = tempfile::tempdir().unwrap();
        let src = dir.path().join("src");
        fs::create_dir_all(&src).unwrap();
        fs::write(src.join("lib.rs"), "pub fn aaa() {}\npub fn bbb() {}").unwrap();

        let db = setup_db(dir.path());
        let result = why_path(db.as_ref(), "aaa", "bbb", 5).unwrap();
        assert!(result.path.is_empty());
    }
}
