// Exact Rust translations of the basic RLV query tests.

use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SENDER_ID, guid};
use libremetaverse_rlv::RlvService;

const OTHER_SENDER: &str = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
const SIT_ID: &str = "00000000-0000-4000-8000-000000000000";
const TP_EXCEPTION: &str = "3d6181b0-6a4b-97ef-18d8-722652995cf1";

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

fn seed_blacklist(h: &RlvHarness, seed: &str) {
    for behavior in seed.split(',').filter(|behavior| !behavior.is_empty()) {
        h.service
            .blacklist()
            .blacklist_behavior(behavior.into())
            .unwrap();
    }
}

fn assert_reply(h: &RlvHarness, expected: &str) {
    assert_eq!(
        h.actions.lock().unwrap().replies,
        vec![(1234, expected.into())]
    );
}

fn get_blacklist_matches(command: &str, seed: &str, expected: &str) -> bool {
    let h = harness();
    seed_blacklist(&h, seed);
    block_on(h.process(&format!("{command}=1234"))).unwrap();
    h.actions.lock().unwrap().replies == vec![(1234, expected.into())]
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:8e1b820c1f2bd3cd 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765 translated
#[test]
fn get_blacklist_all() {
    assert!(get_blacklist_matches(
        "@getblacklist",
        "sendim,recvim",
        "recvim,sendim"
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:64136cd82156035a 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765 translated
#[test]
fn get_blacklist_im_filter() {
    assert!(get_blacklist_matches(
        "@getblacklist:im",
        "sendim,recvim",
        "recvim,sendim"
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:2068bf7f0a131fe8 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765 translated
#[test]
fn get_blacklist_send_filter() {
    assert!(get_blacklist_matches(
        "@getblacklist:send",
        "sendim,recvim",
        "sendim"
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:b86b0c5e67f981c2 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765 translated
#[test]
fn get_blacklist_unmatched_filter() {
    assert!(get_blacklist_matches(
        "@getblacklist:tpto",
        "sendim,recvim",
        ""
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:123b930bb970a1f1 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765 translated
#[test]
fn get_blacklist_empty() {
    assert!(get_blacklist_matches("@getblacklist", "", ""));
}

fn manual_blacklist_matches(seed: &str, expected: &str) -> bool {
    let mut h = harness();
    h.service.set_enable_instant_message_processing(true);
    seed_blacklist(&h, seed);
    block_on(
        h.service
            .process_instant_message("@getblacklist".into(), guid(SENDER_ID), None),
    )
    .unwrap();
    h.actions.lock().unwrap().instant_messages == vec![(guid(SENDER_ID), expected.into())]
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.ManualBlacklist::case:f14641dea0f1de93 4ef9ab9bc3165b99ef6b9cf6ae563210660e83fccf946376217c300a752c724e translated
#[test]
fn manual_blacklist_all() {
    assert!(manual_blacklist_matches("sendim,recvim", "recvim,sendim"));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.ManualBlacklist::case:d25c660357f6ccff 4ef9ab9bc3165b99ef6b9cf6ae563210660e83fccf946376217c300a752c724e translated
#[test]
fn manual_blacklist_empty() {
    assert!(manual_blacklist_matches("", ""));
}

fn debug_matches(setting_name: &str, setting_value: &str) -> bool {
    let h = harness();
    h.queries
        .lock()
        .unwrap()
        .debug_settings
        .insert(setting_name.to_lowercase(), setting_value.into());
    block_on(h.process(&format!("@getdebug_{setting_name}=1234"))).unwrap()
        && h.actions.lock().unwrap().replies == vec![(1234, setting_value.into())]
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/GetDebugQueryTests.cs::GetDebugQueryTests.GetDebug_Default::case:fa77559e30768d15 6554db3b0455887c0224a6f91c7830d6cbf38d5520a65a9b17e26280fcc291f7 translated
#[test]
fn get_debug_known_setting() {
    assert!(debug_matches(
        "RenderResolutionDivisor",
        "RenderResolutionDivisor Success"
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/GetDebugQueryTests.cs::GetDebugQueryTests.GetDebug_Default::case:55694f25ed879d95 6554db3b0455887c0224a6f91c7830d6cbf38d5520a65a9b17e26280fcc291f7 translated
#[test]
fn get_debug_unknown_setting() {
    assert!(debug_matches("Unknown Setting", "Unknown Setting Success"));
}

fn environment_matches(setting_name: &str, setting_value: &str) -> bool {
    let h = harness();
    h.queries
        .lock()
        .unwrap()
        .environment_settings
        .insert(setting_name.to_lowercase(), setting_value.into());
    block_on(h.process(&format!("@getenv_{setting_name}=1234"))).unwrap()
        && h.actions.lock().unwrap().replies == vec![(1234, setting_value.into())]
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/GetEnvQueryTests.cs::GetEnvQueryTests.GetEnv_Default::case:f656b648d00a6d91 cf4270c6c3417690afcf43982c3bdcf815f46ce81f9b6ccaf59377c633a64881 translated
#[test]
fn get_environment_known_setting() {
    assert!(environment_matches("Daytime", "Daytime Success"));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/GetEnvQueryTests.cs::GetEnvQueryTests.GetEnv_Default::case:55694f25ed879d95 cf4270c6c3417690afcf43982c3bdcf815f46ce81f9b6ccaf59377c633a64881 translated
#[test]
fn get_environment_unknown_setting() {
    assert!(environment_matches(
        "Unknown Setting",
        "Unknown Setting Success"
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/GetGroupQueryTests.cs::GetGroupQueryTests.GetGroup_Default::test da65b184d0ef1380274e8e4dfa199c125a1a192b9e76f8fec1d406df18186169 translated
#[test]
fn get_active_group() {
    let h = harness();
    h.queries.lock().unwrap().active_group = Some("Group Name".into());
    assert!(block_on(h.process("@getgroup=1234")).unwrap());
    assert_reply(&h, "Group Name");
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/GetGroupQueryTests.cs::GetGroupQueryTests.GetGroup_NoGroup::test d1da37ae52bd94dac9cd6e031525b57f31ca7e9dc00a69a6e0c4e753741dc9e8 translated
#[test]
fn get_group_without_active_group() {
    let h = harness();
    assert!(block_on(h.process("@getgroup=1234")).unwrap());
    assert_reply(&h, "none");
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/GetSitIdQueryTests.cs::GetSitIdQueryTests.GetSitID::test bfbf6d62c09c4878504aa529805a29fe9689d1e29e7ca3d44bf2346d6b3fbe6b translated
#[test]
fn get_sit_id_when_not_sitting() {
    let h = harness();
    block_on(h.process("@getsitid=1234")).unwrap();
    assert_reply(&h, "NULL_KEY");
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/GetSitIdQueryTests.cs::GetSitIdQueryTests.GetSitID_Default::test 456f8f22b1d2917c3729ed600bdf0b693c0189bd100b9863f4b42b07259110b0 translated
#[test]
fn get_current_sit_id() {
    let h = harness();
    h.queries.lock().unwrap().sit_id = Some(guid(SIT_ID));
    block_on(h.process("@getsitid=1234")).unwrap();
    assert_reply(&h, SIT_ID);
}

fn seed_status(h: &RlvHarness) {
    block_on(h.process("@fly=n")).unwrap();
    block_on(h.process("@tplure=n")).unwrap();
    block_on(h.process(&format!("@tplure:{TP_EXCEPTION}=add"))).unwrap();
    block_on(h.process_from("@tplocal=n", OTHER_SENDER, "Sender 2")).unwrap();
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/GetStatusAllQueryTests.cs::GetStatusAllQueryTests.GetStatusAll::test ee8fac8485db2b5c01abf8664364ca1e13214243f1e661a04d93df680422d596 translated
#[test]
fn get_status_all_senders() {
    let h = harness();
    seed_status(&h);
    block_on(h.process("@getstatusall=1234")).unwrap();
    assert_reply(
        &h,
        "/fly/tplure/tplure:3d6181b0-6a4b-97ef-18d8-722652995cf1/tplocal",
    );
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/GetStatusQueryTests.cs::GetStatusQueryTests.GetStatus::test c538e68277e93b40374dfd86bde9be00e0b82dfad7f4573cc4b0660f15fa5fe4 translated
#[test]
fn get_status_for_sender() {
    let h = harness();
    seed_status(&h);
    block_on(h.process("@getstatus=1234")).unwrap();
    assert_reply(
        &h,
        "/fly/tplure/tplure:3d6181b0-6a4b-97ef-18d8-722652995cf1",
    );
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/GetStatusQueryTests.cs::GetStatusQueryTests.GetStatus_filtered::test 574b7f7c37b4e09e4257e5b02d50b222054216e34b6d1dd3fe6b26127c89b562 translated
#[test]
fn get_status_filtered() {
    let h = harness();
    seed_status(&h);
    block_on(h.process("@getstatus:tp=1234")).unwrap();
    assert_reply(&h, "/tplure/tplure:3d6181b0-6a4b-97ef-18d8-722652995cf1");
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/GetStatusQueryTests.cs::GetStatusQueryTests.GetStatus_customSeparator::test 3bec2e53ea88857d4a1ae8cd6bc6f235f24e00d0773c24ca75a1892adb803527 translated
#[test]
fn get_status_custom_separator() {
    let h = harness();
    seed_status(&h);
    block_on(h.process("@getstatus:; ! =1234")).unwrap();
    assert_reply(
        &h,
        " ! fly ! tplure ! tplure:3d6181b0-6a4b-97ef-18d8-722652995cf1",
    );
}

fn version_num_blacklist_matches(seed: &str, expected: &str) -> bool {
    let h = harness();
    seed_blacklist(&h, seed);
    block_on(h.process("@versionnumbl=1234")).unwrap();
    h.actions.lock().unwrap().replies == vec![(1234, expected.into())]
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/VersionNumBlQueryTests.cs::VersionNumBlQueryTests.VersionNumBL::case:478968a5d14830de 0dbc89f77a6f293efcca217febb2f6b8d224f9ac5e1d6532a56a7df64a7be6e9 translated
#[test]
fn version_number_without_blacklist() {
    assert!(version_num_blacklist_matches(
        "",
        RlvService::RLV_VERSION_NUM
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/VersionNumBlQueryTests.cs::VersionNumBlQueryTests.VersionNumBL::case:8c124ee42e9ab944 0dbc89f77a6f293efcca217febb2f6b8d224f9ac5e1d6532a56a7df64a7be6e9 translated
#[test]
fn version_number_with_blacklist() {
    assert!(version_num_blacklist_matches(
        "sendim,recvim",
        "2040213,recvim,sendim"
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/VersionQueryTests.cs::VersionQueryTests.ManualVersion::test 6f8493b201d69e1449d8311e434736f6f6b2bad04c9fe9c6adf94a94d9cbe597 translated
#[test]
fn manual_version() {
    let mut h = harness();
    h.service.set_enable_instant_message_processing(true);
    block_on(
        h.service
            .process_instant_message("@version".into(), guid(SENDER_ID), None),
    )
    .unwrap();
    assert_eq!(
        h.actions.lock().unwrap().instant_messages,
        vec![(guid(SENDER_ID), RlvService::RLV_VERSION.into())]
    );
}

fn version_query_matches(command: &str, expected: &str) -> bool {
    let h = harness();
    block_on(h.process(&format!("{command}=1234"))).unwrap();
    h.actions.lock().unwrap().replies == vec![(1234, expected.into())]
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/VersionQueryTests.cs::VersionQueryTests.CheckVersions::case:442bdc765ad34e20 f8118590cf64832f30e5e3c927bf8cee42c90d82a3e275554e9c36adb7ad5d30 translated
#[test]
fn version_query_standard() {
    assert!(version_query_matches("@version", RlvService::RLV_VERSION));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/VersionQueryTests.cs::VersionQueryTests.CheckVersions::case:968af293ea2a53a1 f8118590cf64832f30e5e3c927bf8cee42c90d82a3e275554e9c36adb7ad5d30 translated
#[test]
fn version_query_new() {
    assert!(version_query_matches(
        "@versionnew",
        RlvService::RLV_VERSION
    ));
}

// parity-case: LibreMetaverse.Tests/RLV/Queries/VersionQueryTests.cs::VersionQueryTests.CheckVersions::case:ae9a221915e6e1bb f8118590cf64832f30e5e3c927bf8cee42c90d82a3e275554e9c36adb7ad5d30 translated
#[test]
fn version_query_number() {
    assert!(version_query_matches(
        "@versionnum",
        RlvService::RLV_VERSION_NUM
    ));
}
