use dirigent_fermata::core::botignore::BotignoreSet;
use std::fs;
use tempfile::TempDir;

#[test]
fn matches_simple_pattern() {
    let tmp = TempDir::new().unwrap();
    let root = tmp.path();
    fs::write(root.join(".botignore"), ".env\nsecrets/\n").unwrap();

    let set = BotignoreSet::load(root).unwrap();

    let env = root.join(".env");
    fs::write(&env, "").unwrap();
    let m = set.matched(&env).unwrap();
    assert!(m.is_some(), ".env should be matched");
    assert_eq!(m.unwrap().pattern, ".env");
}

#[test]
fn does_not_match_unrelated_files() {
    let tmp = TempDir::new().unwrap();
    let root = tmp.path();
    fs::write(root.join(".botignore"), ".env\n").unwrap();

    let set = BotignoreSet::load(root).unwrap();

    let other = root.join("README.md");
    fs::write(&other, "").unwrap();
    assert!(set.matched(&other).unwrap().is_none());
}

#[test]
fn negation_pattern_excludes() {
    let tmp = TempDir::new().unwrap();
    let root = tmp.path();
    fs::write(root.join(".botignore"), "*.log\n!keep.log\n").unwrap();

    let set = BotignoreSet::load(root).unwrap();

    let blocked = root.join("foo.log");
    fs::write(&blocked, "").unwrap();
    assert!(set.matched(&blocked).unwrap().is_some());

    let allowed = root.join("keep.log");
    fs::write(&allowed, "").unwrap();
    assert!(set.matched(&allowed).unwrap().is_none());
}

#[test]
fn empty_or_missing_botignore_is_ok() {
    let tmp = TempDir::new().unwrap();
    let set = BotignoreSet::load(tmp.path()).unwrap();
    let any = tmp.path().join("anything.txt");
    std::fs::write(&any, "").unwrap();
    assert!(set.matched(&any).unwrap().is_none());
}

#[test]
fn nested_botignore_is_scoped_to_its_directory() {
    // A `.botignore` in a subdirectory only applies under that subdirectory,
    // matching gitignore semantics: a sibling file with the same name at the
    // root is NOT affected.
    let tmp = TempDir::new().unwrap();
    let root = tmp.path();
    fs::create_dir_all(root.join("frontend")).unwrap();
    fs::write(root.join("frontend/.botignore"), "secret.key\n").unwrap();

    let set = BotignoreSet::load(root).unwrap();

    let blocked = root.join("frontend/secret.key");
    fs::write(&blocked, "").unwrap();
    let m = set
        .matched(&blocked)
        .unwrap()
        .expect("frontend/secret.key should match");
    let src = m.source.to_string_lossy().replace('\\', "/");
    assert!(
        src.ends_with("frontend/.botignore"),
        "Rule.source should point at the nested file; was {}",
        src,
    );

    let unblocked = root.join("secret.key");
    fs::write(&unblocked, "").unwrap();
    assert!(
        set.matched(&unblocked).unwrap().is_none(),
        "top-level secret.key should NOT be matched (rule scoped to frontend/)",
    );
}

#[test]
fn nested_botignore_anchored_pattern_is_local() {
    // A leading `/` anchors the pattern to the directory of the .botignore
    // file it's declared in.
    let tmp = TempDir::new().unwrap();
    let root = tmp.path();
    fs::create_dir_all(root.join("frontend")).unwrap();
    fs::write(root.join("frontend/.botignore"), "/secret.key\n").unwrap();

    let set = BotignoreSet::load(root).unwrap();

    let blocked = root.join("frontend/secret.key");
    fs::write(&blocked, "").unwrap();
    assert!(set.matched(&blocked).unwrap().is_some());

    let unblocked = root.join("secret.key");
    fs::write(&unblocked, "").unwrap();
    assert!(
        set.matched(&unblocked).unwrap().is_none(),
        "anchored /secret.key should NOT match outside frontend/",
    );
}

#[test]
fn nested_botignore_overrides_root() {
    let tmp = TempDir::new().unwrap();
    let root = tmp.path();
    fs::write(root.join(".botignore"), "*.log\n").unwrap();
    fs::create_dir_all(root.join("logs")).unwrap();
    fs::write(root.join("logs/.botignore"), "!keep.log\n").unwrap();

    let set = BotignoreSet::load(root).unwrap();

    let blocked = root.join("logs/foo.log");
    fs::write(&blocked, "").unwrap();
    assert!(set.matched(&blocked).unwrap().is_some());

    let kept = root.join("logs/keep.log");
    fs::write(&kept, "").unwrap();
    assert!(
        set.matched(&kept).unwrap().is_none(),
        "logs/.botignore should un-ignore keep.log",
    );
}
