//! External-caller smoke. Exercises the [`klieo_eval`] public API
//! from outside-crate scope so the surface stays usable for
//! downstream consumers (e.g. `klieo-compliance`'s
//! `regulation_recall_quality_test`, which will migrate to this
//! crate after publish).

use klieo_eval::{score_recall, RecallSample};

fn ids(items: &[&str]) -> Vec<String> {
    items.iter().map(|s| (*s).to_string()).collect()
}

#[test]
fn typical_regulation_recall_corpus_scores_high() {
    let samples = vec![
        RecallSample::new(
            "ICT risk management framework",
            ids(&["dora-art-5", "dora-art-6"]),
            ids(&["dora-art-5", "dora-art-6", "ai-act-art-6", "gdpr-art-6"]),
        ),
        RecallSample::new(
            "high-risk AI systems",
            ids(&["ai-act-art-6", "ai-act-art-16"]),
            ids(&["ai-act-art-6", "dora-art-5", "ai-act-art-16"]),
        ),
        RecallSample::new(
            "lawfulness of processing",
            ids(&["gdpr-art-6"]),
            ids(&["gdpr-art-6", "dora-art-5", "dora-art-6"]),
        ),
    ];
    let report = score_recall(&samples, 5);
    assert!((report.hit_rate() - 1.0).abs() < 1e-9);
    assert!(report.mean_reciprocal_rank() > 0.99);
    assert!(report.mean_ndcg_at_k() > 0.95);
    assert_eq!(report.per_query.len(), 3);
    for row in &report.per_query {
        assert!(row.first_hit_rank.is_some());
    }
}

#[test]
fn partial_failure_surfaces_per_query_detail() {
    let samples = vec![
        RecallSample::new("hit", ids(&["a"]), ids(&["a"])),
        RecallSample::new("miss", ids(&["b"]), ids(&["x", "y", "z"])),
    ];
    let report = score_recall(&samples, 5);
    assert_eq!(report.per_query[0].first_hit_rank, Some(1));
    assert_eq!(report.per_query[1].first_hit_rank, None);
    assert!((report.hit_rate() - 0.5).abs() < 1e-9);
}
