// Exact Rust translations of the CurrentOutfitFolderTests fixture in
// LibreMetaverse.Tests/CurrentOutfitFolderTests.cs.
// Source SHA-256: 07177fff27fbee0d0714286c652253985add3a9401a50e8d7a829ce6c2b3b7a86

use libremetaverse::appearance::{CurrentOutfitFolder, ICurrentOutfitPolicy};
use libremetaverse::{
    GridClient, InventoryItem, InventoryWearable, NameValue, NameValueClassType,
    NameValueSendtoType, NameValueValueType, Primitive,
};
use libremetaverse_compat_tests::block_on;
use libremetaverse_types::compat::Object;
use libremetaverse_types::{AssetType, Error, UUID};
use std::sync::Arc;

struct TestPolicy;
impl ICurrentOutfitPolicy for TestPolicy {}

fn outfit_folder() -> CurrentOutfitFolder {
    CurrentOutfitFolder::new(Some(Arc::new(GridClient::new().unwrap()))).unwrap()
}

// parity-case: LibreMetaverse.Tests/CurrentOutfitFolderTests.cs::CurrentOutfitFolderTests.Constructor_WithNullClient_ThrowsArgumentNullException::test 243079029ec81f92ffbc587007a2421389963f72c7843786c5b9a8634a7ddca3 translated
#[test]
fn constructor_with_null_client_throws_argument_null_exception() {
    match CurrentOutfitFolder::new(None) {
        Err(error) => assert_eq!(error, Error::ArgumentNull),
        Ok(_) => panic!("expected ArgumentNull for client"),
    }
}

// parity-case: LibreMetaverse.Tests/CurrentOutfitFolderTests.cs::CurrentOutfitFolderTests.Dispose_CalledOnce_DoesNotThrow::test 1d0daac0bfa091bc3c3bffddc32a1511295dd7101f8ab5dfbf305b13b9ac7405 translated
#[test]
fn dispose_called_once_does_not_throw() {
    outfit_folder().dispose().unwrap();
}

// parity-case: LibreMetaverse.Tests/CurrentOutfitFolderTests.cs::CurrentOutfitFolderTests.Dispose_CalledMultipleTimes_DoesNotThrow::test 124b41c342a295f02e9d5991d1dead0ff3e9a780f96424b88f75117ca206460b translated
#[test]
fn dispose_called_multiple_times_does_not_throw() {
    let cof = outfit_folder();
    cof.dispose().unwrap();
    cof.dispose().unwrap();
}

// parity-case: LibreMetaverse.Tests/CurrentOutfitFolderTests.cs::CurrentOutfitFolderTests.MaxClothingLayers_Returns60::test e35e779b342fdb54bb7f5b2061f70c35ccc3f7f9ba87f48b2697f24c10f94397 translated
#[test]
fn max_clothing_layers_returns_60() {
    assert_eq!(outfit_folder().max_clothing_layers(), 60);
}

// parity-case: LibreMetaverse.Tests/CurrentOutfitFolderTests.cs::CurrentOutfitFolderTests.COF_InitiallyNull::test 2dee4e58f3f53e50c5389ba0594ea0b063af55871eefae49e99bdd4b5c28e552 translated
#[test]
fn cof_initially_null() {
    assert!(outfit_folder().cof().is_none());
}

// parity-case: LibreMetaverse.Tests/CurrentOutfitFolderTests.cs::CurrentOutfitFolderTests.AddPolicy_WithValidPolicy_ReturnsAddedPolicy::test 747db5d674a6cb0bc54bcb9d32501d5bab49e0df5e5e39f3781f88d5100ed244 translated
#[test]
fn add_policy_with_valid_policy_returns_added_policy() {
    let cof = outfit_folder();
    let policy: Arc<dyn ICurrentOutfitPolicy> = Arc::new(TestPolicy);
    let result = cof.add_policy(Arc::clone(&policy)).unwrap();
    assert!(Arc::ptr_eq(&result, &policy));
}

// parity-case: LibreMetaverse.Tests/CurrentOutfitFolderTests.cs::CurrentOutfitFolderTests.RemovePolicy_WithValidPolicy_DoesNotThrow::test 41f61b917da0410be01b346644a76bc9c800f78d1e1ba6ef805b14cea1b4d00d translated
#[test]
fn remove_policy_with_valid_policy_does_not_throw() {
    let cof = outfit_folder();
    let policy: Arc<dyn ICurrentOutfitPolicy> = Arc::new(TestPolicy);
    cof.add_policy(Arc::clone(&policy)).unwrap();
    cof.remove_policy(policy).unwrap();
}

// parity-case: LibreMetaverse.Tests/CurrentOutfitFolderTests.cs::CurrentOutfitFolderTests.RemovePolicy_WithNonAddedPolicy_DoesNotThrow::test 4add41578d3d5340618cb29ed6969b84c5c3a80e6da09ccb03bc6872a6b6689a translated
#[test]
fn remove_policy_with_non_added_policy_does_not_throw() {
    let cof = outfit_folder();
    cof.remove_policy(Arc::new(TestPolicy)).unwrap();
}

// parity-case: LibreMetaverse.Tests/CurrentOutfitFolderTests.cs::CurrentOutfitFolderTests.ResolveInventoryLink_WithNonLinkItem_ReturnsSameItem::test 7430a64883f3938afe7da1b126e4ee460cbf2485e2d51035273b4ca8fd150960 translated
#[test]
fn resolve_inventory_link_with_non_link_item_returns_same_item() {
    let cof = outfit_folder();
    let mut wearable = InventoryWearable::new(UUID::random().unwrap()).unwrap();
    wearable.base.set_asset_type(AssetType::Clothing);
    wearable.base.set_asset_uuid(UUID::random().unwrap());
    let item = Arc::new(wearable.base);
    let result = cof
        .resolve_inventory_link(Arc::clone(&item))
        .unwrap()
        .unwrap();
    assert!(Arc::ptr_eq(&result, &item));
}

// parity-case: LibreMetaverse.Tests/CurrentOutfitFolderTests.cs::CurrentOutfitFolderTests.ResolveInventoryLink_WithLinkItemNotInStore_ReturnsNull::test 21e0dae8c038d2381eef736ad30d48fc0247e0a55b86e75de02982290a3a9bd0 translated
#[test]
fn resolve_inventory_link_with_link_item_not_in_store_returns_null() {
    let mut client = GridClient::new().unwrap();
    let owner = client.self_().agent_id();
    let cof = CurrentOutfitFolder::new(Some(Arc::new(client))).unwrap();
    let mut link = InventoryItem::new_with_uuid(UUID::random().unwrap()).unwrap();
    link.set_asset_type(AssetType::Link);
    link.set_asset_uuid(UUID::random().unwrap());
    link.base.set_owner_id(owner);
    assert!(
        cof.resolve_inventory_link(Arc::new(link))
            .unwrap()
            .is_none()
    );
}

// parity-case: LibreMetaverse.Tests/CurrentOutfitFolderTests.cs::CurrentOutfitFolderTests.GetAttachmentItemID_WithNoNameValues_ReturnsZero::test c9e017a587c37b694484feda4fab81ef7f2bb098bbf8f96f3cefbb21f1a568d8 translated
#[test]
fn get_attachment_item_id_with_no_name_values_returns_zero() {
    let mut prim = Primitive::new_with_constructor().unwrap();
    prim.name_values = None;
    assert_eq!(
        CurrentOutfitFolder::get_attachment_item_id(prim).unwrap(),
        UUID::zero()
    );
}

// parity-case: LibreMetaverse.Tests/CurrentOutfitFolderTests.cs::CurrentOutfitFolderTests.GetAttachmentItemID_WithAttachItemID_ReturnsCorrectUUID::test 23e6be11056b93d75424c23030e1d2082545f686d12c0aa14f66991664e347e8 translated
#[test]
fn get_attachment_item_id_with_attach_item_id_returns_correct_uuid() {
    let expected = UUID::random().unwrap();
    let value = NameValue::new_with_string_value_type_class_type_sendto_type_object(
        "AttachItemID".into(),
        NameValueValueType::String,
        NameValueClassType::ReadOnly,
        NameValueSendtoType::SimViewer,
        Object::String(expected.to_string()),
    )
    .unwrap();
    let mut prim = Primitive::new_with_constructor().unwrap();
    prim.name_values = Some(vec![value]);
    assert_eq!(
        CurrentOutfitFolder::get_attachment_item_id(prim).unwrap(),
        expected
    );
}

// parity-case: LibreMetaverse.Tests/CurrentOutfitFolderTests.cs::CurrentOutfitFolderTests.GetAttachmentItemID_WithoutAttachItemID_ReturnsZero::test 7ee12fc59c8b5e5cb074e18c2af48c0f1b1d7be0937db65a7056e29e114b691f translated
#[test]
fn get_attachment_item_id_without_attach_item_id_returns_zero() {
    let value = NameValue::new_with_string_value_type_class_type_sendto_type_object(
        "SomeOtherValue".into(),
        NameValueValueType::String,
        NameValueClassType::ReadOnly,
        NameValueSendtoType::SimViewer,
        Object::String("test".into()),
    )
    .unwrap();
    let mut prim = Primitive::new_with_constructor().unwrap();
    prim.name_values = Some(vec![value]);
    assert_eq!(
        CurrentOutfitFolder::get_attachment_item_id(prim).unwrap(),
        UUID::zero()
    );
}

// parity-case: LibreMetaverse.Tests/CurrentOutfitFolderTests.cs::CurrentOutfitFolderTests.IsObjectDescendentOf_WithZeroParentId_ReturnsFalse::test a878c220510aacbf61ebfb192952e26d96343312fcf9648e57e270e29aaa9d5d translated
#[test]
fn is_object_descendent_of_with_zero_parent_id_returns_false() {
    let cof = outfit_folder();
    let item = InventoryItem::new_with_uuid(UUID::random().unwrap()).unwrap();
    assert!(!block_on(cof.is_object_descendent_of(item.base, UUID::zero(), None)).unwrap());
}

// parity-case: LibreMetaverse.Tests/CurrentOutfitFolderTests.cs::CurrentOutfitFolderTests.IsObjectDescendentOf_WithDirectParent_ReturnsTrue::test ac3af5edef5ee67058a91a990bfde38e616d00919b0cd8e0b5f7345f7d8dab6c translated
#[test]
fn is_object_descendent_of_with_direct_parent_returns_true() {
    let cof = outfit_folder();
    let parent = UUID::random().unwrap();
    let mut item = InventoryItem::new_with_uuid(UUID::random().unwrap()).unwrap();
    item.base.set_parent_uuid(parent);
    assert!(block_on(cof.is_object_descendent_of(item.base, parent, None)).unwrap());
}

// parity-case: LibreMetaverse.Tests/CurrentOutfitFolderTests.cs::CurrentOutfitFolderTests.FetchParent_WithZeroParentUUID_ReturnsNull::test ee6cc0cc9a48ec07afb8bd7fa8e1c53c2db258be11e2848ee5752e41eb34e45a translated
#[test]
fn fetch_parent_with_zero_parent_uuid_returns_null() {
    let cof = outfit_folder();
    let mut item = InventoryItem::new_with_uuid(UUID::random().unwrap()).unwrap();
    item.base.set_parent_uuid(UUID::zero());
    assert!(
        block_on(cof.fetch_parent(item.base, None))
            .unwrap()
            .is_none()
    );
}

// parity-case: LibreMetaverse.Tests/CurrentOutfitFolderTests.cs::CurrentOutfitFolderTests.GetCurrentOutfitLinks_WithNullCOF_ReturnsEmptyList::test 5c0d475ccd4423bc099eb141f36061fdfaa589fd36d27c907d03a9d0be3f6f48 translated
#[test]
fn get_current_outfit_links_with_null_cof_returns_empty_list() {
    let links = block_on(outfit_folder().get_current_outfit_links(None)).unwrap();
    assert!(links.is_empty());
}
