// Exact Rust translations of NotifyQueryTests.

use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, guid};
use libremetaverse_rlv::{RlvAttachmentPoint, RlvWearableType};

const ITEM_1: &str = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
const ITEM_2: &str = "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const ITEM_3: &str = "cccccccc-cccc-4ccc-8ccc-cccccccccccc";
const PRIM: &str = "aaaaaaaa-aaaa-4aaa-8aaa-ffffffffffff";

fn harness() -> RlvHarness {
    RlvHarness::new().expect("RlvService constructor")
}

fn process(h: &RlvHarness, commands: &[&str]) {
    for command in commands {
        block_on(h.process(command)).unwrap();
    }
}

fn replies_match(h: &RlvHarness, expected: &[(i32, &str)]) -> bool {
    h.actions.lock().unwrap().replies
        == expected
            .iter()
            .map(|(channel, text)| (*channel, (*text).into()))
            .collect::<Vec<_>>()
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.Notify::test 082ff4cd00faf29a73aca158d4e24ed9fd3e7844ed6cefbf962d8727846a3c27 translated
#[test]
fn notify_every_restriction() {
    let h = harness();
    process(
        &h,
        &[
            "@notify:1234=add",
            "@sendim=n",
            "@alwaysrun=n",
            "@sendim:group_name=add",
        ],
    );
    assert!(replies_match(
        &h,
        &[
            (1234, "/notify:1234=n"),
            (1234, "/sendim=n"),
            (1234, "/alwaysrun=n"),
            (1234, "/sendim:group_name=n"),
        ],
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyFiltered::test e00e51aeadd0d7a107105684129a6ae74fbf918be4c563d92d7cdaa223d2c03c translated
#[test]
fn notify_filtered() {
    let h = harness();
    process(
        &h,
        &[
            "@notify:1234;run=add",
            "@sendim=n",
            "@alwaysrun=n",
            "@sendim:group_name=add",
        ],
    );
    assert!(replies_match(&h, &[(1234, "/alwaysrun=n")]));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyMultiCommand::test 77f3950214a1bd1e3816fa6f7b0ca69727e9e18be5fb7b37f19490408ca023dc translated
#[test]
fn notify_multi_command() {
    let h = harness();
    process(
        &h,
        &[
            "@notify:1234=add",
            "@sendim=n,sendim:group_name=add,alwaysrun=n",
        ],
    );
    assert!(replies_match(
        &h,
        &[
            (1234, "/notify:1234=n"),
            (1234, "/sendim=n"),
            (1234, "/sendim:group_name=n"),
            (1234, "/alwaysrun=n"),
        ],
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyMultiChannels::test 12a0a6e0a0a6632960de98236670e063f2c1aa16cf6b6c8d718bde0e0abfd9b9 translated
#[test]
fn notify_multiple_channels() {
    let h = harness();
    process(&h, &["@notify:1234=add", "@notify:12345=add", "@sendim=n"]);
    assert!(replies_match(
        &h,
        &[
            (1234, "/notify:1234=n"),
            (1234, "/notify:12345=n"),
            (12345, "/notify:12345=n"),
            (1234, "/sendim=n"),
            (12345, "/sendim=n"),
        ],
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyMultiChannelsFiltered::test bff8ca8465c2299d0d2ef60adfa4164270d08cee7223361bb27b86a7e4daeec9 translated
#[test]
fn notify_multiple_channels_filtered() {
    let h = harness();
    process(
        &h,
        &["@notify:1234=add", "@notify:12345;im=add", "@sendim=n"],
    );
    assert!(replies_match(
        &h,
        &[
            (1234, "/notify:1234=n"),
            (1234, "/notify:12345;im=n"),
            (1234, "/sendim=n"),
            (12345, "/sendim=n"),
        ],
    ));
}

fn notify_synonym(command: &str, expected_reply: &str) -> bool {
    let h = harness();
    process(&h, &["@notify:1234=add", command]);
    replies_match(&h, &[(1234, "/notify:1234=n"), (1234, expected_reply)])
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:9e893d263294d04d 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_camdistmax() {
    assert!(notify_synonym("@camdistmax:123=n", "/camdistmax:123=n"));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:fc6b17eb4e9e7a00 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_setcam_avdistmax() {
    assert!(notify_synonym(
        "@setcam_avdistmax:123=n",
        "/setcam_avdistmax:123=n"
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:b37376c5865a6fe8 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_camdistmin() {
    assert!(notify_synonym("@camdistmin:123=n", "/camdistmin:123=n"));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:5d497faea315b624 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_setcam_avdistmin() {
    assert!(notify_synonym(
        "@setcam_avdistmin:123=n",
        "/setcam_avdistmin:123=n"
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:282fa0139ccbba29 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_camunlock() {
    assert!(notify_synonym("@camunlock=n", "/camunlock=n"));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:f08c6eb7b4d12fac 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_setcam_unlock() {
    assert!(notify_synonym("@setcam_unlock=n", "/setcam_unlock=n"));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:37f0f73ed7492dd0 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_camtextures() {
    assert!(notify_synonym(
        "@camtextures:1cdbc6a2-ae6b-3130-9348-3d3b1ca84c53=n",
        "/camtextures:1cdbc6a2-ae6b-3130-9348-3d3b1ca84c53=n",
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:d75917941e63732c 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_touchfar() {
    assert!(notify_synonym("@touchfar:5=n", "/touchfar:5=n"));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:2f72da33fdbcd8be 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_fartouch() {
    assert!(notify_synonym("@fartouch:5=n", "/fartouch:5=n"));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyClear_Filtered::test f3e0550a53faca13679421318eee85f010c1b8668e3edfae6e2548d39dbcafd7 translated
#[test]
fn notify_clear_filtered() {
    let h = harness();
    process(&h, &["@notify:1234=add", "@fly=n", "@clear=fly"]);
    assert!(replies_match(
        &h,
        &[
            (1234, "/notify:1234=n"),
            (1234, "/fly=n"),
            (1234, "/fly=y"),
            (1234, "/clear:fly"),
        ],
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyClear::test 61d7419956a83be04eeb13557c6a2120419b2f0f1c529149c4fb57871bb6506e translated
#[test]
fn notify_clear() {
    let h = harness();
    block_on(h.process_from("@notify:1234=add", ITEM_3, "Main")).unwrap();
    process(&h, &["@fly=n", "@clear"]);
    assert!(replies_match(
        &h,
        &[
            (1234, "/notify:1234=n"),
            (1234, "/fly=n"),
            (1234, "/fly=y"),
            (1234, "/clear"),
        ],
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyInventoryOffer::test 2bbac63ab86ec77f6d0a4558a14ee913a7f44930364476a89e02cd5ec80191b9 translated
#[test]
fn notify_inventory_offer() {
    let h = harness();
    process(&h, &["@notify:1234=add"]);
    block_on(
        h.service
            .report_inventory_offer_accepted("#RLV/~MyCuffs".into(), None),
    )
    .unwrap();
    block_on(
        h.service
            .report_inventory_offer_accepted("Objects/New Folder (3)".into(), None),
    )
    .unwrap();
    block_on(
        h.service
            .report_inventory_offer_declined("#RLV/Foo/Bar".into(), None),
    )
    .unwrap();
    assert!(replies_match(
        &h,
        &[
            (1234, "/notify:1234=n"),
            (1234, "/accepted_in_rlv inv_offer ~MyCuffs"),
            (1234, "/accepted_in_inv inv_offer Objects/New Folder (3)"),
            (1234, "/declined inv_offer Foo/Bar"),
        ],
    ));
}

fn report_sit_and_unsit(h: &RlvHarness) {
    block_on(h.service.report_sit(Some(Some(guid(ITEM_3))), None)).unwrap();
    block_on(h.service.report_unsit(Some(Some(guid(ITEM_3))), None)).unwrap();
    block_on(h.service.report_sit(None, None)).unwrap();
    block_on(h.service.report_unsit(None, None)).unwrap();
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySitStandLegal::test 83a07a88a0386982c854a0223b64dd5c417f1a55a038e4ceba8f487983daadaf translated
#[test]
fn notify_sit_and_stand_legal() {
    let h = harness();
    process(&h, &["@notify:1234=add"]);
    report_sit_and_unsit(&h);
    assert!(replies_match(
        &h,
        &[
            (1234, "/notify:1234=n"),
            (
                1234,
                "/sat object legally 11111111-1111-4111-8111-111111111111",
            ),
            (
                1234,
                "/unsat object legally 11111111-1111-4111-8111-111111111111",
            ),
            (1234, "/sat ground legally"),
            (1234, "/unsat ground legally"),
        ],
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySitStandWithRestrictions::test 166e2087aa0652bdd427e1908bc338659ec1d4dc8065c016612696d1f5dfd000 translated
#[test]
fn notify_sit_and_stand_illegal() {
    let h = harness();
    process(&h, &["@sit=n", "@unsit=n", "@notify:1234=add"]);
    report_sit_and_unsit(&h);
    assert!(replies_match(
        &h,
        &[
            (1234, "/notify:1234=n"),
            (
                1234,
                "/sat object illegally 11111111-1111-4111-8111-111111111111",
            ),
            (
                1234,
                "/unsat object illegally 11111111-1111-4111-8111-111111111111",
            ),
            (1234, "/sat ground illegally"),
            (1234, "/unsat ground illegally"),
        ],
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyWear::test 9529acb9f3e1c335a50f8de6d63cc5711921de962546ff868811279d05826399 translated
#[test]
fn notify_wear_legal() {
    let h = harness();
    process(&h, &["@notify:1234=add"]);
    block_on(
        h.service
            .report_item_worn(guid(ITEM_2), false, RlvWearableType::Skin, None),
    )
    .unwrap();
    block_on(
        h.service
            .report_item_worn(guid(ITEM_3), true, RlvWearableType::Tattoo, None),
    )
    .unwrap();
    assert!(replies_match(
        &h,
        &[
            (1234, "/notify:1234=n"),
            (1234, "/worn legally skin"),
            (1234, "/worn legally tattoo"),
        ],
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyWear_Illegal::test 65bfc1db698470cf56dd8c6811e85ae373d1fca95cdbf82be66b7e32da311a2f translated
#[test]
fn notify_wear_illegal() {
    let h = harness();
    process(&h, &["@addoutfit:skin=n", "@notify:1234=add"]);
    block_on(
        h.service
            .report_item_worn(guid(ITEM_1), false, RlvWearableType::Skin, None),
    )
    .unwrap();
    assert!(replies_match(
        &h,
        &[(1234, "/notify:1234=n"), (1234, "/worn illegally skin")],
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyUnWear::test 340b60b8038dcd55320dc9aedc16beb9193e731ba7b659ca3cb2951a2d19b7ac translated
#[test]
fn notify_unwear_legal() {
    let h = harness();
    process(&h, &["@notify:1234=add"]);
    block_on(h.service.report_item_unworn(
        guid(ITEM_1),
        guid(ITEM_2),
        false,
        RlvWearableType::Skin,
        None,
    ))
    .unwrap();
    block_on(h.service.report_item_unworn(
        guid(ITEM_1),
        guid(ITEM_3),
        true,
        RlvWearableType::Tattoo,
        None,
    ))
    .unwrap();
    assert!(replies_match(
        &h,
        &[
            (1234, "/notify:1234=n"),
            (1234, "/unworn legally skin"),
            (1234, "/unworn legally tattoo"),
        ],
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyUnWear_illegal::test e7056e6e145430eb2180edb92593f59c07bcbdfa21629b1ca29ac93b2fca975e translated
#[test]
fn notify_unwear_illegal() {
    let h = harness();
    process(&h, &["@remoutfit:skin=n", "@notify:1234=add"]);
    block_on(h.service.report_item_unworn(
        guid(ITEM_1),
        guid(ITEM_1),
        false,
        RlvWearableType::Skin,
        None,
    ))
    .unwrap();
    assert!(replies_match(
        &h,
        &[(1234, "/notify:1234=n"), (1234, "/unworn illegally skin")],
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyAttached::test dc5239c77b9169cf3833c5a1dc765b381efe833f15b34ac7e57173c0a640942a translated
#[test]
fn notify_attached_legal() {
    let h = harness();
    process(&h, &["@notify:1234=add"]);
    block_on(
        h.service
            .report_item_attached(guid(ITEM_1), false, RlvAttachmentPoint::Chest, None),
    )
    .unwrap();
    block_on(h.service.report_item_attached(
        guid(ITEM_2),
        true,
        RlvAttachmentPoint::AvatarCenter,
        None,
    ))
    .unwrap();
    assert!(replies_match(
        &h,
        &[
            (1234, "/notify:1234=n"),
            (1234, "/attached legally Chest"),
            (1234, "/attached legally Avatar Center"),
        ],
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyAttached_Illegal::test b56de057dece9cb8ece795d13d6bc42e7825d62f09f967f37a4dbf262d2b4456 translated
#[test]
fn notify_attached_illegal() {
    let h = harness();
    process(&h, &["@addattach:chest=n", "@notify:1234=add"]);
    block_on(
        h.service
            .report_item_attached(guid(ITEM_1), false, RlvAttachmentPoint::Chest, None),
    )
    .unwrap();
    assert!(replies_match(
        &h,
        &[
            (1234, "/notify:1234=n"),
            (1234, "/attached illegally Chest"),
        ],
    ));
}

fn report_detached(h: &RlvHarness, folder: &str, shared: bool, point: RlvAttachmentPoint) {
    block_on(h.service.report_item_detached(
        guid(ITEM_1),
        guid(PRIM),
        guid(folder),
        shared,
        point,
        None,
    ))
    .unwrap();
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyDetached::test a741cec23a985028b3dc2b09195255276a96e4f07fc4fe5f8cca6c1e3c940d71 translated
#[test]
fn notify_detached_legal() {
    let h = harness();
    process(&h, &["@notify:1234=add"]);
    report_detached(&h, ITEM_2, false, RlvAttachmentPoint::Chest);
    report_detached(&h, ITEM_3, true, RlvAttachmentPoint::Skull);
    assert!(replies_match(
        &h,
        &[
            (1234, "/notify:1234=n"),
            (1234, "/detached legally Chest"),
            (1234, "/detached legally Skull"),
        ],
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyDetached_Illegal::test 1a4c9475a3b91a975b9861685dcaf899505b4f6727257618f9add9cecd3df54d translated
#[test]
fn notify_detached_illegal() {
    let h = harness();
    process(&h, &["@remattach:chest=n", "@notify:1234=add"]);
    report_detached(&h, ITEM_1, false, RlvAttachmentPoint::Chest);
    assert!(replies_match(
        &h,
        &[
            (1234, "/notify:1234=n"),
            (1234, "/detached illegally Chest"),
        ],
    ));
}
