use super::*;

#[test]
fn test_apply_browser_headers_enabled() {
    let mut req = reqwest::Client::new().get("http://example.com");
    let headers = std::collections::HashMap::new();
    let config = HeaderConfig::browser_compat();
    req = apply_browser_headers_to_request(req, &headers, &config, 0);
    let req_built = req.build().unwrap();

    assert!(req_built.headers().contains_key("User-Agent"));
    assert!(req_built.headers().contains_key("Accept"));
    assert!(req_built.headers().contains_key("Accept-Language"));
    assert!(req_built.headers().contains_key("Accept-Encoding"));
    let profile = scanclient::tls_profiles::rotate(0);
    assert_eq!(
        req_built
            .headers()
            .get("User-Agent")
            .and_then(|value| value.to_str().ok()),
        Some(profile.user_agent)
    );
    assert_eq!(
        req_built
            .headers()
            .get("Accept-Encoding")
            .and_then(|value| value.to_str().ok()),
        Some(profile.accept_encoding)
    );
    assert_eq!(
        req_built
            .headers()
            .get("Sec-Fetch-Mode")
            .and_then(|value| value.to_str().ok()),
        Some("navigate")
    );
    assert_eq!(
        req_built
            .headers()
            .get("Sec-Fetch-Dest")
            .and_then(|value| value.to_str().ok()),
        Some("document")
    );
    assert_eq!(
        req_built
            .headers()
            .get("Sec-Fetch-User")
            .and_then(|value| value.to_str().ok()),
        Some("?1")
    );
}

#[test]
fn test_apply_browser_headers_disabled() {
    let mut req = reqwest::Client::new().get("http://example.com");
    let headers = std::collections::HashMap::new();
    let config = HeaderConfig::disabled();
    req = apply_browser_headers_to_request(req, &headers, &config, 0);
    let req_built = req.build().unwrap();

    assert_eq!(
        req_built.headers().len(),
        0,
        "disabled header config should not add any headers"
    );
}

#[test]
fn test_apply_browser_headers_preserves_existing() {
    let mut headers = std::collections::HashMap::new();
    headers.insert("User-Agent".to_string(), "custom-agent".to_string());

    let mut req = reqwest::Client::new().get("http://example.com");
    req = req.header("User-Agent", "custom-agent");

    let config = HeaderConfig::browser_compat();
    req = apply_browser_headers_to_request(req, &headers, &config, 0);
    let req_built = req.build().unwrap();

    assert_eq!(
        req_built
            .headers()
            .get("User-Agent")
            .expect("operation should succeed"),
        "custom-agent"
    );
    assert!(req_built.headers().contains_key("Accept")); // Should add others
}

#[test]
fn test_apply_browser_headers_accepts_full_catalog_profile_name() {
    let mut req = reqwest::Client::new().get("http://example.com");
    let headers = std::collections::HashMap::new();
    let mut config = HeaderConfig::browser_compat();
    config.profile_name = Some("chrome-android".to_string());
    req = apply_browser_headers_to_request(req, &headers, &config, 0);
    let req_built = req.build().unwrap();
    let facts = guise_profiles::profile_facts(guise_profiles::StealthProfile::ChromeAndroid);

    assert_eq!(
        req_built
            .headers()
            .get("User-Agent")
            .and_then(|value| value.to_str().ok()),
        Some(facts.user_agent)
    );
    assert_eq!(
        req_built
            .headers()
            .get("Accept-Language")
            .and_then(|value| value.to_str().ok()),
        Some(facts.accept_language)
    );
    assert_eq!(
        req_built
            .headers()
            .get("Accept-Encoding")
            .and_then(|value| value.to_str().ok()),
        Some(facts.accept_encoding)
    );
}

#[test]
fn test_apply_browser_headers_accepts_legacy_catalog_alias() {
    let mut req = reqwest::Client::new().get("http://example.com");
    let headers = std::collections::HashMap::new();
    let mut config = HeaderConfig::browser_compat();
    config.profile_name = Some("ie11".to_string());
    req = apply_browser_headers_to_request(req, &headers, &config, 0);
    let req_built = req.build().unwrap();
    let facts = guise_profiles::profile_facts(guise_profiles::StealthProfile::Ie11Windows);

    assert_eq!(
        req_built
            .headers()
            .get("User-Agent")
            .and_then(|value| value.to_str().ok()),
        Some(facts.user_agent)
    );
    assert_eq!(
        req_built
            .headers()
            .get("Accept")
            .and_then(|value| value.to_str().ok()),
        Some(facts.accept)
    );
    assert_eq!(
        req_built
            .headers()
            .get("Accept-Encoding")
            .and_then(|value| value.to_str().ok()),
        Some(facts.accept_encoding)
    );
}

#[test]
fn test_apply_browser_headers_preserves_mixed_case_existing() {
    let mut headers = std::collections::HashMap::new();
    headers.insert("USER-AGENT".to_string(), "custom-agent".to_string());
    headers.insert("aCcEpT".to_string(), "application/json".to_string());
    headers.insert("ACCEPT-LANGUAGE".to_string(), "fr-FR".to_string());
    headers.insert("Accept-Encoding".to_string(), "identity".to_string());

    let mut req = reqwest::Client::new().get("http://example.com");
    req = req
        .header("USER-AGENT", "custom-agent")
        .header("aCcEpT", "application/json")
        .header("ACCEPT-LANGUAGE", "fr-FR")
        .header("Accept-Encoding", "identity");

    let config = HeaderConfig::browser_compat();
    req = apply_browser_headers_to_request(req, &headers, &config, 0);
    let req_built = req.build().unwrap();

    assert_eq!(
        req_built
            .headers()
            .get("User-Agent")
            .and_then(|value| value.to_str().ok()),
        Some("custom-agent")
    );
    assert_eq!(
        req_built
            .headers()
            .get("Accept")
            .and_then(|value| value.to_str().ok()),
        Some("application/json")
    );
    assert_eq!(
        req_built
            .headers()
            .get("Accept-Language")
            .and_then(|value| value.to_str().ok()),
        Some("fr-FR")
    );
    assert_eq!(
        req_built
            .headers()
            .get("Accept-Encoding")
            .and_then(|value| value.to_str().ok()),
        Some("identity")
    );
}

#[test]
fn test_apply_browser_headers_map_accepts_full_catalog_profile_name() {
    let mut headers = std::collections::HashMap::new();
    let mut config = HeaderConfig::browser_compat();
    config.profile_name = Some("chrome-android".to_string());
    apply_browser_headers(&mut headers, &config, 0);
    let facts = guise_profiles::profile_facts(guise_profiles::StealthProfile::ChromeAndroid);

    assert_eq!(
        headers.get("User-Agent").map(String::as_str),
        Some(facts.user_agent)
    );
    assert_eq!(
        headers.get("Accept-Language").map(String::as_str),
        Some(facts.accept_language)
    );
    assert_eq!(
        headers.get("Accept-Encoding").map(String::as_str),
        Some(facts.accept_encoding)
    );
    assert_eq!(
        headers.get("Sec-Fetch-Mode").map(String::as_str),
        Some("navigate")
    );
    assert_eq!(
        headers.get("Sec-Fetch-Dest").map(String::as_str),
        Some("document")
    );
    assert_eq!(
        headers.get("Sec-Fetch-User").map(String::as_str),
        Some("?1")
    );
}

#[test]
fn test_apply_browser_headers_map_preserves_mixed_case_existing() {
    let mut headers = std::collections::HashMap::new();
    headers.insert("USER-AGENT".to_string(), "custom-agent".to_string());
    headers.insert("aCcEpT".to_string(), "application/json".to_string());
    headers.insert("ACCEPT-LANGUAGE".to_string(), "fr-FR".to_string());
    headers.insert("Accept-Encoding".to_string(), "identity".to_string());

    let config = HeaderConfig::browser_compat();
    apply_browser_headers(&mut headers, &config, 0);

    assert_eq!(
        headers.get("USER-AGENT").map(String::as_str),
        Some("custom-agent")
    );
    assert_eq!(
        headers.get("aCcEpT").map(String::as_str),
        Some("application/json")
    );
    assert_eq!(
        headers.get("ACCEPT-LANGUAGE").map(String::as_str),
        Some("fr-FR")
    );
    assert_eq!(
        headers.get("Accept-Encoding").map(String::as_str),
        Some("identity")
    );
    assert!(!headers.contains_key("User-Agent"));
    assert!(!headers.contains_key("Accept"));
    assert!(!headers.contains_key("Accept-Language"));
}

#[test]
fn test_apply_browser_headers_map_waf_bypass_preserves_existing_case_insensitive() {
    let mut headers = std::collections::HashMap::new();
    headers.insert("x-forwarded-for".to_string(), "203.0.113.7".to_string());
    headers.insert("TRUE-CLIENT-IP".to_string(), "203.0.113.8".to_string());

    let mut config = HeaderConfig::disabled();
    config.enable_waf_bypass = true;
    config.waf_bypass_ip = Some("10.0.0.1".to_string());
    apply_browser_headers(&mut headers, &config, 0);

    assert_eq!(
        headers.get("x-forwarded-for").map(String::as_str),
        Some("203.0.113.7")
    );
    assert_eq!(
        headers.get("TRUE-CLIENT-IP").map(String::as_str),
        Some("203.0.113.8")
    );
    assert!(!headers.contains_key("X-Forwarded-For"));
    assert!(!headers.contains_key("True-Client-IP"));
    assert!(headers.contains_key("CF-Connecting-IP"));
    assert!(headers.contains_key("X-Real-IP"));
}

#[test]
fn test_random_delay() {
    let delay_zero = random_delay(0);
    assert_eq!(delay_zero, Duration::from_millis(0));

    let delay = random_delay(100);
    assert!(delay < Duration::from_millis(100));
}
