//! Integration tests for RDAP domain checking
//!
//! These tests verify that the RDAP implementation correctly identifies
//! whether well-known domains are taken or available across different TLDs.

use lazydomain::checker::RdapClient;
use lazydomain::types::{CheckStatus, Domain};

/// Helper to create RDAP client
fn create_client() -> RdapClient {
    RdapClient::new().expect("Failed to create RDAP client")
}

/// Helper to check domain and return status
async fn check_domain_status(domain_name: &str, tld: &str) -> CheckStatus {
    let client = create_client();
    let domain = Domain::new(domain_name, tld).expect("Valid domain");
    let result = client
        .check_domain(&domain)
        .await
        .expect("Check should not fail");
    result.status
}

// ============================================================================
// Regression Tests for Known Taken Domains
// ============================================================================

#[tokio::test]
async fn test_google_com_is_taken() {
    let status = check_domain_status("google", "com").await;
    assert_eq!(
        status,
        CheckStatus::Taken,
        "google.com should be taken (registered by Google)"
    );
}

#[tokio::test]
async fn test_google_net_is_taken() {
    // REGRESSION: This was incorrectly showing as Available due to wrong RDAP endpoint
    // Fixed by using https://rdap.verisign.com/net/v1 instead of /com/v1
    let status = check_domain_status("google", "net").await;
    assert_eq!(
        status,
        CheckStatus::Taken,
        "google.net should be taken (was showing Available due to bug)"
    );
}

#[tokio::test]
async fn test_google_org_is_taken() {
    let status = check_domain_status("google", "org").await;
    assert_eq!(
        status,
        CheckStatus::Taken,
        "google.org should be taken"
    );
}

#[tokio::test]
async fn test_google_io_is_taken() {
    let status = check_domain_status("google", "io").await;
    assert_eq!(
        status,
        CheckStatus::Taken,
        "google.io should be taken"
    );
}

#[tokio::test]
async fn test_microsoft_com_is_taken() {
    let status = check_domain_status("microsoft", "com").await;
    assert_eq!(
        status,
        CheckStatus::Taken,
        "microsoft.com should be taken"
    );
}

#[tokio::test]
async fn test_microsoft_net_is_taken() {
    let status = check_domain_status("microsoft", "net").await;
    assert_eq!(
        status,
        CheckStatus::Taken,
        "microsoft.net should be taken"
    );
}

#[tokio::test]
async fn test_amazon_com_is_taken() {
    let status = check_domain_status("amazon", "com").await;
    assert_eq!(
        status,
        CheckStatus::Taken,
        "amazon.com should be taken"
    );
}

#[tokio::test]
async fn test_facebook_com_is_taken() {
    let status = check_domain_status("facebook", "com").await;
    assert_eq!(
        status,
        CheckStatus::Taken,
        "facebook.com should be taken"
    );
}

#[tokio::test]
async fn test_google_ai_is_taken() {
    let status = check_domain_status("google", "ai").await;
    assert_eq!(
        status,
        CheckStatus::Taken,
        "google.ai should be taken (Google uses this domain)"
    );
}

#[tokio::test]
async fn test_openai_ai_is_taken() {
    let status = check_domain_status("openai", "ai").await;
    assert_eq!(
        status,
        CheckStatus::Taken,
        "openai.ai should be taken (OpenAI's main domain)"
    );
}

#[tokio::test]
async fn test_microsoft_ai_is_taken() {
    let status = check_domain_status("microsoft", "ai").await;
    assert_eq!(
        status,
        CheckStatus::Taken,
        "microsoft.ai should be taken (Microsoft uses this domain)"
    );
}

// ============================================================================
// Tests for Different TLD Registries
// ============================================================================

#[tokio::test]
async fn test_verisign_com_tld() {
    // Verisign handles .com
    let status = check_domain_status("example", "com").await;
    assert_eq!(
        status,
        CheckStatus::Taken,
        "example.com is a reserved domain (should be taken)"
    );
}

#[tokio::test]
async fn test_verisign_net_tld() {
    // Verisign handles .net with separate endpoint
    let status = check_domain_status("example", "net").await;
    assert_eq!(
        status,
        CheckStatus::Taken,
        "example.net is a reserved domain (should be taken)"
    );
}

#[tokio::test]
async fn test_public_interest_registry_org() {
    // Public Interest Registry handles .org
    let status = check_domain_status("example", "org").await;
    assert_eq!(
        status,
        CheckStatus::Taken,
        "example.org is a reserved domain (should be taken)"
    );
}

#[tokio::test]
async fn test_identity_digital_io() {
    // Identity Digital handles .io
    let status = check_domain_status("github", "io").await;
    assert_eq!(
        status,
        CheckStatus::Taken,
        "github.io should be taken (GitHub Pages)"
    );
}

// ============================================================================
// Tests for Available Domains (Likely Garbage Names)
// ============================================================================

#[tokio::test]
async fn test_random_gibberish_probably_available() {
    // Using a very long random string that's unlikely to be registered
    let status = check_domain_status("xyzabc123thisdomainshouldnotexist999", "com").await;
    // Could be Available or Error (if RDAP fails), but should NOT be Taken
    assert!(
        status != CheckStatus::Taken,
        "Random gibberish domain should not be taken"
    );
}

// ============================================================================
// Tests for Multi-TLD Consistency
// ============================================================================

#[tokio::test]
async fn test_tld_endpoints_are_independent() {
    // REGRESSION: Ensure .com and .net use different endpoints
    // This test checks that we're hitting the right RDAP servers
    
    let com_status = check_domain_status("google", "com").await;
    let net_status = check_domain_status("google", "net").await;
    
    // Both should be taken
    assert_eq!(com_status, CheckStatus::Taken, "google.com should be taken");
    assert_eq!(net_status, CheckStatus::Taken, "google.net should be taken");
    
    // The key test: if we were using the wrong endpoint for .net,
    // it would return Available instead of Taken
}

// ============================================================================
// Tests for Error Handling
// ============================================================================

#[tokio::test]
async fn test_unsupported_tld_returns_error() {
    // Test a TLD we don't have RDAP support for
    let status = check_domain_status("example", "xyz123notreal").await;
    assert_eq!(
        status,
        CheckStatus::Error,
        "Unsupported TLD should return Error status"
    );
}

// ============================================================================
// Tests for Domain Validation
// ============================================================================

#[tokio::test]
async fn test_invalid_domain_name() {
    // Test that invalid domain names are handled
    let result = Domain::new("", "com");
    assert!(
        result.is_err(),
        "Empty domain name should return error"
    );
}

#[tokio::test]
async fn test_invalid_tld() {
    let result = Domain::new("example", "");
    assert!(
        result.is_err(),
        "Empty TLD should return error"
    );
}

// ============================================================================
// Benchmarking / Performance Tests
// ============================================================================

#[tokio::test]
async fn test_multiple_tlds_for_same_domain() {
    // Test checking multiple TLDs for the same domain name
    let domain_name = "google";
    let tlds = vec!["com", "net", "org", "io"];
    
    for tld in tlds {
        let status = check_domain_status(domain_name, tld).await;
        assert_eq!(
            status,
            CheckStatus::Taken,
            "google.{} should be taken",
            tld
        );
    }
}

// ============================================================================
// DNS Verification Tests (RDAP 404 Fallback)
// ============================================================================

#[tokio::test]
async fn test_google_co_dns_verification() {
    // REGRESSION: google.co returns 404 from RDAP but resolves via DNS
    // This tests that our DNS fallback correctly identifies it as taken
    let status = check_domain_status("google", "co").await;
    assert_eq!(
        status,
        CheckStatus::Taken,
        "google.co should be taken (DNS verified) even if RDAP returns 404"
    );
}

#[tokio::test]
async fn test_amazon_co_dns_verification() {
    // Another .co domain that may have incomplete RDAP data
    let status = check_domain_status("amazon", "co").await;
    assert_eq!(
        status,
        CheckStatus::Taken,
        "amazon.co should be taken (DNS verified)"
    );
}

#[tokio::test]
async fn test_twitter_co_dns_verification() {
    // Test another well-known .co domain
    let status = check_domain_status("twitter", "co").await;
    assert_eq!(
        status,
        CheckStatus::Taken,
        "twitter.co should be taken (DNS verified)"
    );
}

#[tokio::test]
async fn test_unregistered_co_domain_via_dns() {
    // Test that truly unregistered .co domains show as available
    // Using very long gibberish that's unlikely to be registered
    let status = check_domain_status("thisdomainshoulddefinitelynotexist12345xyz", "co").await;
    assert!(
        status == CheckStatus::Available || status == CheckStatus::Error,
        "Unregistered .co domain should be Available or Error, not Taken"
    );
}

// ============================================================================
// Real-World Scenario Tests
// ============================================================================

#[tokio::test]
async fn test_popular_tech_companies() {
    let companies = vec![
        ("apple", "com"),
        ("amazon", "com"),
        ("google", "com"),
        ("microsoft", "com"),
        ("meta", "com"),
    ];
    
    for (company, tld) in companies {
        let status = check_domain_status(company, tld).await;
        assert_eq!(
            status,
            CheckStatus::Taken,
            "{}.{} should be taken",
            company,
            tld
        );
    }
}

#[tokio::test]
async fn test_well_known_domains_across_tlds() {
    // Test domains that are commonly registered across multiple TLDs
    let test_cases = vec![
        ("github", "com", CheckStatus::Taken),
        ("github", "io", CheckStatus::Taken),
        ("twitter", "com", CheckStatus::Taken),
        ("reddit", "com", CheckStatus::Taken),
    ];
    
    for (domain, tld, expected) in test_cases {
        let status = check_domain_status(domain, tld).await;
        assert_eq!(
            status, expected,
            "{}.{} status mismatch",
            domain, tld
        );
    }
}
