use libremetaverse::animesh::AnimeshManager;
use libremetaverse::appearance::CurrentOutfitFolder;
use libremetaverse::{
    AgentManager, AppearanceManagerWearableData, AssetDownload, AssetManager, AssetUpload,
    ChatEventArgs, ChatType, InventoryException, InventoryItem, InventoryManager,
    TeleportEventArgs,
};
use libremetaverse_types::compat::{CancellationToken, EventHandler, Subscription};
use libremetaverse_types::{AssetType, AttachmentPoint, UUID};

fn member_id<T>(result: Result<T, libremetaverse::Error>) -> &'static str {
    result
        .err()
        .expect("failure-only shim unexpectedly returned a value")
        .csharp_member()
        .expect("failure-only shim error")
}

fn compile_bot_and_animation_calls(
    agent: &AgentManager,
    chat_type: ChatType,
    animation: UUID,
    chat_handler: EventHandler<ChatEventArgs>,
) {
    let _: Subscription = agent.subscribe_chat_from_simulator(chat_handler);
    let _ = agent.chat(String::new(), 0, chat_type, Some(true));
    let _ = agent.animation_start(animation, true);
}

async fn compile_outfit_call(
    outfit: &CurrentOutfitFolder,
    item: InventoryItem,
    point: AttachmentPoint,
    token: CancellationToken,
) {
    let _ = outfit.attach(item, point, true, Some(token)).await;
}

async fn compile_inventory_call(
    inventory: &InventoryManager,
    item_id: UUID,
    owner_id: UUID,
    token: CancellationToken,
) {
    let _ = inventory
        .request_fetch_inventory_with_uuid_uuid_cancellation_token_6647b02a(
            item_id,
            owner_id,
            Some(token),
        )
        .await;
}

async fn compile_asset_download_call(
    assets: &AssetManager,
    asset_id: UUID,
    asset_type: AssetType,
    token: CancellationToken,
) {
    let _ = assets
        .request_asset_with_uuid_asset_type_boolean_cancellation_token(
            asset_id,
            asset_type,
            true,
            Some(token),
        )
        .await;
}

async fn compile_teleport_call(
    agent: &AgentManager,
    landmark: UUID,
    token: CancellationToken,
    handler: EventHandler<TeleportEventArgs>,
) {
    let _: Subscription = agent.subscribe_teleport_progress(handler);
    let _ = agent
        .teleport_with_uuid_cancellation_token(landmark, Some(token))
        .await;
}

fn compile_animesh_call(animesh: &AnimeshManager, object_id: UUID) {
    let _ = animesh.get_player(object_id);
    let _ = animesh.update(1.0 / 60.0);
}

#[test]
fn avatar_facing_flows_have_typed_callable_signatures() {
    let _ = compile_bot_and_animation_calls;
    let _ = compile_outfit_call;
    let _ = compile_inventory_call;
    let _ = compile_asset_download_call;
    let _ = compile_teleport_call;
    let _ = compile_animesh_call;
}

#[test]
fn avatar_facing_constructors_fail_with_catalog_ids() {
    assert_eq!(
        member_id(AssetDownload::new()),
        "M:LibreMetaverse.AssetDownload.#ctor"
    );
    assert_eq!(
        member_id(AssetUpload::new()),
        "M:LibreMetaverse.AssetUpload.#ctor"
    );
    assert_eq!(
        member_id(AppearanceManagerWearableData::new()),
        "M:LibreMetaverse.AppearanceManager.WearableData.#ctor"
    );
    assert_eq!(
        member_id(InventoryException::new_with_constructor()),
        "M:LibreMetaverse.InventoryException.#ctor"
    );
}
