//! Exact Rust translations of the non-inventory RLV command tests.

use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, TeleportCall, guid};

const OBJECT: &str = "00000000-0000-4000-8000-000000000000";
const OTHER_SENDER: &str = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";

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

// parity-case: LibreMetaverse.Tests/RLV/Commands/AdjustHeightCommandTests.cs::AdjustHeightCommandTests.AdjustHeight::test fb3adb86988b10b2d3fe9223324f8a3c1ba7b8c2ea909ee6b57b38c590fed372 translated
#[test]
fn adjust_height() {
    let h = harness();
    block_on(h.process("@adjustheight:4.3;1.25=force")).unwrap();
    assert_eq!(
        h.actions.lock().unwrap().adjusted_heights,
        vec![(4.3, 1.25, 0.0)]
    );
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/AdjustHeightCommandTests.cs::AdjustHeightCommandTests.AdjustHeight_WithDelta::test 1f37a125fd9df8585740d37c711888dfcd92460d86c19077f771d7f3fab54264 translated
#[test]
fn adjust_height_with_delta() {
    let h = harness();
    block_on(h.process("@adjustheight:4.3;1.25;12.34=force")).unwrap();
    assert_eq!(
        h.actions.lock().unwrap().adjusted_heights,
        vec![(4.3, 1.25, 12.34)]
    );
}

fn seed_clear(h: &RlvHarness) {
    block_on(h.process("@tploc=n")).unwrap();
    block_on(h.process("@tplm=n")).unwrap();
    block_on(h.process("@unsit=n")).unwrap();
    block_on(h.process("@fly=n")).unwrap();
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/ClearCommandTests.cs::ClearCommandTests.Clear::test 865d022233930e9582fec5b0e99063f15506a339c430755aba83706b594182ad translated
#[test]
fn clear() {
    let h = harness();
    seed_clear(&h);
    block_on(h.process("@clear")).unwrap();
    assert!(
        h.service
            .restrictions()
            .find_restrictions(None, None)
            .unwrap()
            .is_empty()
    );
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/ClearCommandTests.cs::ClearCommandTests.Clear_CaseInSensitive::test b70296f9d2b6c9eb8c6dd6e560056ab8320d746a991fafec858812fc2ebb3141 translated
#[test]
fn clear_is_case_insensitive() {
    let h = harness();
    seed_clear(&h);
    block_on(h.process("@cLEaR")).unwrap();
    assert!(
        h.service
            .restrictions()
            .find_restrictions(None, None)
            .unwrap()
            .is_empty()
    );
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/ClearCommandTests.cs::ClearCommandTests.Clear_SenderBased::test 1ae70737411e18626227c0b15181572c1c623eefce0a8fa1a874b2229c44c38e translated
#[test]
fn clear_is_sender_based() {
    let h = harness();
    block_on(h.process("@tploc=n")).unwrap();
    block_on(h.process("@tplm=n")).unwrap();
    block_on(h.process_from("@unsit=n", OTHER_SENDER, "Sender 2")).unwrap();
    block_on(h.process_from("@fly=n", OTHER_SENDER, "Sender 2")).unwrap();
    block_on(h.process_from("@clear", OTHER_SENDER, "Sender 2")).unwrap();
    let permissions = h.service.permissions();
    assert_eq!(
        [
            permissions.can_tp_loc().unwrap(),
            permissions.can_tp_lm().unwrap(),
            permissions.can_unsit().unwrap(),
            permissions.can_fly().unwrap()
        ],
        [false, false, true, true]
    );
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/ClearCommandTests.cs::ClearCommandTests.Clear_Filtered::test e0f0b5a42c3baf92fef6a8d4fc2c60dbd6963db6f844fed55b06968f0c9e543f translated
#[test]
fn clear_is_filtered() {
    let h = harness();
    seed_clear(&h);
    block_on(h.process("@clear=tp")).unwrap();
    let permissions = h.service.permissions();
    assert_eq!(
        [
            permissions.can_tp_loc().unwrap(),
            permissions.can_tp_lm().unwrap(),
            permissions.can_unsit().unwrap(),
            permissions.can_fly().unwrap()
        ],
        [true, true, false, false]
    );
}

fn set_debug(setting: &str, value: &str) -> Vec<(String, String)> {
    let h = harness();
    block_on(h.process(&format!("@setdebug_{setting}:{value}=force"))).unwrap();
    h.actions.lock().unwrap().debug_settings.clone()
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/SetDebugCommandTests.cs::SetDebugCommandTests.SetDebug_Default::case:fa77559e30768d15 abcee425068df326a3258ab4d881218e6eee52523fa5d306b191308e85dfff3d translated
#[test]
fn set_debug_known_setting() {
    assert_eq!(
        set_debug("RenderResolutionDivisor", "RenderResolutionDivisor Success"),
        vec![(
            "renderresolutiondivisor".into(),
            "RenderResolutionDivisor Success".into()
        )]
    );
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/SetDebugCommandTests.cs::SetDebugCommandTests.SetDebug_Default::case:55694f25ed879d95 abcee425068df326a3258ab4d881218e6eee52523fa5d306b191308e85dfff3d translated
#[test]
fn set_debug_unknown_setting() {
    assert_eq!(
        set_debug("Unknown Setting", "Unknown Setting Success"),
        vec![("unknown setting".into(), "Unknown Setting Success".into())]
    );
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/SetDebugCommandTests.cs::SetDebugCommandTests.SetDebug_Invalid::test 2e0595319ba8e2c9a8280c5b034363ad7998eb740cb6b7fff3d75bb0167c6464 translated
#[test]
fn set_debug_rejects_empty_name() {
    let h = harness();
    assert!(!block_on(h.process("@setdebug_:42=force")).unwrap());
    assert!(h.actions.lock().unwrap().debug_settings.is_empty());
}

fn set_env(setting: &str, value: &str) -> Vec<(String, String)> {
    let h = harness();
    block_on(h.process(&format!("@setenv_{setting}:{value}=force"))).unwrap();
    h.actions.lock().unwrap().environment_settings.clone()
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/SetEnvCommandTests.cs::SetEnvCommandTests.SetEnv_Default::case:f656b648d00a6d91 836c1332ca9c4f645e5c9dca8b4a2b967d55fd8148901b05ce5d741e665ab7e1 translated
#[test]
fn set_environment_known_setting() {
    assert_eq!(
        set_env("Daytime", "Daytime Success"),
        vec![("daytime".into(), "Daytime Success".into())]
    );
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/SetEnvCommandTests.cs::SetEnvCommandTests.SetEnv_Default::case:55694f25ed879d95 836c1332ca9c4f645e5c9dca8b4a2b967d55fd8148901b05ce5d741e665ab7e1 translated
#[test]
fn set_environment_unknown_setting() {
    assert_eq!(
        set_env("Unknown Setting", "Unknown Setting Success"),
        vec![("unknown setting".into(), "Unknown Setting Success".into())]
    );
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/SetGroupCommandTests.cs::SetGroupCommandTests.SetGroup_ByName::test fae27e58cd981f5471f4c2b8356bb07aa5e76a57aaf0882d0dbfb86360e077e3 translated
#[test]
fn set_group_by_name() {
    let h = harness();
    block_on(h.process("@setgroup:Group Name=force")).unwrap();
    assert_eq!(
        h.actions.lock().unwrap().group_names,
        vec![("Group Name".into(), None)]
    );
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/SetGroupCommandTests.cs::SetGroupCommandTests.SetGroup_ByNameAndRole::test 408442b86bb8259eb9bbb4cf8a5d3b0830c7ba9357fa04cb6e851511a7a24df1 translated
#[test]
fn set_group_by_name_and_role() {
    let h = harness();
    block_on(h.process("@setgroup:Group Name;Admin Role=force")).unwrap();
    assert_eq!(
        h.actions.lock().unwrap().group_names,
        vec![("Group Name".into(), Some("Admin Role".into()))]
    );
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/SetGroupCommandTests.cs::SetGroupCommandTests.SetGroup_ById::test 27f13c52c8c5e2e4298fee3f4322f9906d5f82e900aa5f46c9a8ffac3a6dfae7 translated
#[test]
fn set_group_by_id() {
    let h = harness();
    block_on(h.process(&format!("@setgroup:{OBJECT}=force"))).unwrap();
    assert_eq!(
        h.actions.lock().unwrap().group_ids,
        vec![(guid(OBJECT), None)]
    );
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/SetGroupCommandTests.cs::SetGroupCommandTests.SetGroup_ByIdAndRole::test e18fd0c318ebd4f9a189418449568b3a34b8f7d3a0097f100a7253c4d5a31bde translated
#[test]
fn set_group_by_id_and_role() {
    let h = harness();
    block_on(h.process(&format!("@setgroup:{OBJECT};Admin Role=force"))).unwrap();
    assert_eq!(
        h.actions.lock().unwrap().group_ids,
        vec![(guid(OBJECT), Some("Admin Role".into()))]
    );
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/SetRotCommandTests.cs::SetRotCommandTests.SetRot::test c3302d63cdda9d72b85dad2749e2684cc26d51c72ddc6ace8275911f8ba67ef4 translated
#[test]
fn set_rotation() {
    let h = harness();
    block_on(h.process("@setrot:1.5=force")).unwrap();
    assert_eq!(h.actions.lock().unwrap().rotations, vec![1.5]);
}

fn sit_harness(is_sitting: bool, exists: bool) -> RlvHarness {
    let h = harness();
    h.queries.lock().unwrap().is_sitting = is_sitting;
    h.queries
        .lock()
        .unwrap()
        .object_exists
        .insert(guid(OBJECT), exists);
    h
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_Default::test 24e45ba898cb8ed0919369d07a39d0b21982fa4fc4c41eb4835ba765c05e2469 translated
#[test]
fn force_sit() {
    let h = sit_harness(false, true);
    block_on(h.process(&format!("@sit:{OBJECT}=force"))).unwrap();
    assert_eq!(h.actions.lock().unwrap().sits, vec![guid(OBJECT)]);
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_RestrictedUnsit_WhileStanding::test 8d179277f6a7f98ead813de7bd02ab5146b46ce240d1d5e4a69037885e5f626a translated
#[test]
fn force_sit_with_unsit_restricted_while_standing() {
    let h = sit_harness(false, true);
    block_on(h.process("@unsit=n")).unwrap();
    block_on(h.process(&format!("@sit:{OBJECT}=force"))).unwrap();
    assert_eq!(h.actions.lock().unwrap().sits, vec![guid(OBJECT)]);
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_RestrictedUnsit_WhileSeated::test 1f2debd6e644c86698577e1c04db96d6aac43267ceae8de9f28435b62ff92817 translated
#[test]
fn force_sit_rejects_unsit_restriction_while_seated() {
    let h = sit_harness(true, true);
    block_on(h.process("@unsit=n")).unwrap();
    assert!(!block_on(h.process(&format!("@sit:{OBJECT}=force"))).unwrap());
    assert!(h.actions.lock().unwrap().sits.is_empty());
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_RestrictedSit::test 8ac0964fc07bb5e860123ce8de1102c2254ffde28f246896d81f7524c3c87021 translated
#[test]
fn force_sit_rejects_sit_restriction() {
    let h = sit_harness(true, true);
    block_on(h.process("@sit=n")).unwrap();
    assert!(!block_on(h.process(&format!("@sit:{OBJECT}=force"))).unwrap());
    assert!(h.actions.lock().unwrap().sits.is_empty());
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_RestrictedStandTp::test bc0c259477ef5f1e5a76b1081f604ba421c82340f738e37fd52b91a421037cf6 translated
#[test]
fn force_sit_rejects_standtp_restriction() {
    let h = sit_harness(true, true);
    block_on(h.process("@standtp=n")).unwrap();
    assert!(!block_on(h.process(&format!("@sit:{OBJECT}=force"))).unwrap());
    assert!(h.actions.lock().unwrap().sits.is_empty());
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_InvalidObject::test 787bfe6fefe3895b4bcb5da027ffeac70bf67c3c7a295dbbf7e1526156290040 translated
#[test]
fn force_sit_rejects_invalid_object() {
    let h = sit_harness(false, false);
    assert!(!block_on(h.process(&format!("@sit:{OBJECT}=force"))).unwrap());
    assert!(h.actions.lock().unwrap().sits.is_empty());
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/SitGroundCommandTests.cs::SitGroundCommandTests.ForceSitGround::test 2319cd49aaae5ac824bc5ffd4f33a5e4f3f684ebec1dc1f1732071eb44ee1cb8 translated
#[test]
fn force_sit_ground() {
    let h = harness();
    assert!(block_on(h.process("@sitground=force")).unwrap());
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/SitGroundCommandTests.cs::SitGroundCommandTests.ForceSitGround_RestrictedSit::test 5ac661e9f7fa93cf6ca76aa69f6d84ac61ebd22f26620203f084777010b6de4d translated
#[test]
fn force_sit_ground_rejects_sit_restriction() {
    let h = harness();
    block_on(h.process("@sit=n")).unwrap();
    assert!(!block_on(h.process("@sitground=force")).unwrap());
}

fn teleport(command: &str) -> Vec<TeleportCall> {
    let h = harness();
    block_on(h.process(command)).unwrap();
    h.actions.lock().unwrap().teleports.clone()
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_Default::test 1613e723da60f84dfb54a7345b96566a055a9b7a017e66b0929d6f37c04b62a3 translated
#[test]
fn teleport_default() {
    assert_eq!(
        teleport("@tpto:1.5/2.5/3.5=force"),
        vec![TeleportCall {
            x: 1.5,
            y: 2.5,
            z: 3.5,
            region: None,
            look_at: None
        }]
    );
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_WithRegion::test 50c5f63c5cb0da221846fd7c0c7f2d471bef2aa2ab203a9b5bdb4eceeb3d97bf translated
#[test]
fn teleport_with_region() {
    assert_eq!(
        teleport("@tpto:Region Name/1.5/2.5/3.5=force"),
        vec![TeleportCall {
            x: 1.5,
            y: 2.5,
            z: 3.5,
            region: Some("Region Name".into()),
            look_at: None
        }]
    );
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_WithRegionAndLookAt::test c9030189de7acdad0db5c8f83e49ee0433ec0588a35436ab39cdcf40a4fd4d36 translated
#[test]
#[allow(clippy::approx_constant)] // Exact C# fixture literal, not a PI approximation.
fn teleport_with_region_and_look_at() {
    assert_eq!(
        teleport("@tpto:Region Name/1.5/2.5/3.5;3.1415=force"),
        vec![TeleportCall {
            x: 1.5,
            y: 2.5,
            z: 3.5,
            region: Some("Region Name".into()),
            look_at: Some(Some(3.1415))
        }]
    );
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_RestrictedUnsit::test 4dc00a1048593f7468271a4262cf311a3516ea4a53e288eeca69d1297dafc9f2 translated
#[test]
fn teleport_rejects_unsit_restriction() {
    let h = harness();
    block_on(h.process("@unsit=n")).unwrap();
    assert!(!block_on(h.process("@tpto:1.5/2.5/3.5=force")).unwrap());
    assert!(h.actions.lock().unwrap().teleports.is_empty());
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_RestrictedTpLoc::test 3e1ecc1d04973a496edf9d156e52ba76a93ff431181a3ece93c0e4f82884895a translated
#[test]
fn teleport_rejects_tploc_restriction() {
    let h = harness();
    block_on(h.process("@tploc=n")).unwrap();
    assert!(!block_on(h.process("@tpto:1.5/2.5/3.5=force")).unwrap());
    assert!(h.actions.lock().unwrap().teleports.is_empty());
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/UnsitCommandTests.cs::UnsitCommandTests.ForceUnSit::test 2f91e1112e1c4e97b79a4dc7bcd4d4a85f13125bd636f81147ce5b396366ebed translated
#[test]
fn force_unsit() {
    let h = harness();
    assert!(block_on(h.process("@unsit=force")).unwrap());
}

// parity-case: LibreMetaverse.Tests/RLV/Commands/UnsitCommandTests.cs::UnsitCommandTests.ForceUnSit_RestrictedUnsit::test 2ecf210dc83b06018cdcf44cb44bdf43f1040133e7523542a2e1126d6d98004f translated
#[test]
fn force_unsit_rejects_unsit_restriction() {
    let h = harness();
    block_on(h.process("@unsit=n")).unwrap();
    assert!(!block_on(h.process("@unsit=force")).unwrap());
}
