use libremetaverse::http::{DownloadManager, DownloadRequest};
use libremetaverse::{
    CapsRateLimiter, ConnectionSettings, GridClient, HttpCapsClientProgressReport,
    IBakingTextureProvider, LoginCredential, LoginProgressEventArgs, NetworkManager,
    NetworkManagerDisconnectType, Settings, TexturePipeline, TexturePipelineSettings,
    UDPPacketBuffer,
};
use libremetaverse_types::compat::{CancellationToken, EventHandler, IProgress, Subscription, Uri};

async fn compile_login_shutdown_flows(
    network: &NetworkManager,
    limiter: &CapsRateLimiter,
    credential: LoginCredential,
) {
    let token = CancellationToken::default();
    let _ = network
        .login_with_login_credential_string_string_cancellation_token(
            credential,
            String::new(),
            String::new(),
            Some(token.clone()),
        )
        .await;
    let _ = limiter.acquire(Uri(String::new()), Some(token)).await;
    let _ = network
        .shutdown_with_disconnect_type_string_7641243c(
            NetworkManagerDisconnectType::ClientInitiated,
            String::new(),
        )
        .await;
}

async fn compile_request_settings_flows(
    downloads: &DownloadManager,
    texture_pipeline: &TexturePipeline,
    settings: &Settings,
    request: DownloadRequest,
    progress: Box<dyn IProgress<HttpCapsClientProgressReport>>,
) {
    let token = CancellationToken::default();
    let _ = downloads
        .download_with_uri_i_progress_cancellation_token(Uri(String::new()), progress, token)
        .await;
    let _ = downloads.queue_download_with_download_request(request);
    let _ = texture_pipeline.shutdown();
    let _ = settings.connection();
}

fn compile_object_safe_texture_request(
    provider: &dyn IBakingTextureProvider,
    texture_id: libremetaverse_types::UUID,
) {
    drop(provider.request_texture(texture_id, Some(CancellationToken::default())));
}

#[test]
fn runtime_flows_have_typed_callable_signatures() {
    let _: fn(&NetworkManager, EventHandler<LoginProgressEventArgs>) -> Subscription =
        NetworkManager::subscribe_login_progress;
    let _: fn(GridClient) -> Result<Settings, libremetaverse::Error> = Settings::new;
    let _ = compile_login_shutdown_flows;
    let _ = compile_request_settings_flows;
    let _ = compile_object_safe_texture_request;
}

#[test]
fn client_and_settings_construct_without_starting_runtime_work() {
    let mut client = GridClient::new().expect("GridClient constructor");
    assert_eq!(client.settings().timing().login_timeout, 60_000);
    assert_eq!(
        client.lifecycle_state(),
        libremetaverse::ClientLifecycleState::Active
    );
    assert!(!client.cancellation_token().is_cancellation_requested());

    let connection = ConnectionSettings::new().expect("ConnectionSettings constructor");
    assert_eq!(connection.login_server, Settings::AGNI_LOGIN_SERVER);
    assert!(!connection.mfa_enabled);

    let texture = TexturePipelineSettings::new().expect("TexturePipelineSettings constructor");
    assert!(texture.enabled);
    assert!(texture.use_http_textures);
    assert_eq!(texture.max_concurrent_downloads, 4);
    assert_eq!(texture.request_timeout, 45_000);

    client
        .dispose_with_method()
        .expect("idempotent client disposal");
    client
        .dispose_with_method()
        .expect("repeated client disposal");
    assert_eq!(
        client.lifecycle_state(),
        libremetaverse::ClientLifecycleState::Disposed
    );

    let _limiter = CapsRateLimiter::new_with_constructor().expect("CAPS rate limiter");
    let udp_buffer = UDPPacketBuffer::new_with_constructor().expect("UDP packet buffer");
    assert_eq!(udp_buffer.data.len(), 4096);
    assert_eq!(udp_buffer.data_length, 0);
    assert_eq!(udp_buffer.remote_end_point, "0.0.0.0:0".parse().unwrap());
}
