//! Integration test for the `check_name_stream` API.

use std::cell::RefCell;

use onym::transport::test_support::{Canned, MockTransport};
use onym::types::Status;
use onym::{check_name_stream, default_tlds};

#[tokio::test]
async fn streams_one_result_per_source() {
    let name = "example";
    let mut mock = MockTransport::new()
        .json(
            &format!("https://crates.io/api/v1/crates/{name}"),
            Canned::NotFound,
        )
        .json(
            &format!("https://pypi.org/pypi/{name}/json"),
            Canned::NotFound,
        )
        .json(
            &format!("https://registry.npmjs.org/{name}"),
            Canned::NotFound,
        )
        .head(&format!("https://github.com/{name}"), Canned::NotFound);

    for tld in default_tlds() {
        let domain = format!("{name}.{tld}");
        let primary = first_rdap_endpoint(&tld);
        mock = mock.json(&format!("{primary}{domain}"), Canned::NotFound);
    }

    let collected = RefCell::new(Vec::new());
    check_name_stream(&mock, name, &default_tlds(), |result| {
        collected.borrow_mut().push(result);
    })
    .await;

    let collected = collected.into_inner();
    let expected_sources = expected_source_set();
    let actual_sources: std::collections::HashSet<_> =
        collected.iter().map(|r| r.source.clone()).collect();
    assert_eq!(actual_sources, expected_sources);
    for r in &collected {
        assert!(
            matches!(r.status, Status::Free),
            "source {} not Free",
            r.source
        );
    }
}

fn expected_source_set() -> std::collections::HashSet<String> {
    let mut s: std::collections::HashSet<String> = ["crates.io", "pypi", "npm", "github"]
        .iter()
        .map(|s| s.to_string())
        .collect();
    for tld in default_tlds() {
        s.insert(format!(".{tld}"));
    }
    s
}

/// Returns the primary RDAP endpoint base URL for a TLD by replicating the
/// adapter's mapping. Keep this in sync with `src/sources/rdap.rs::endpoints_for`.
fn first_rdap_endpoint(tld: &str) -> &'static str {
    match tld {
        "io" | "ai" => "https://rdap.identitydigital.services/rdap/domain/",
        "dev" | "app" | "page" | "new" | "foo" | "day" | "how" | "soy" => {
            "https://pubapi.registry.google/rdap/domain/"
        }
        "com" | "net" => "https://rdap.verisign.com/com/v1/domain/",
        "org" => "https://rdap.publicinterestregistry.org/rdap/domain/",
        "co" => "https://rdap.nic.co/domain/",
        _ => "https://rdap.org/domain/",
    }
}
