//! Milestone 10 integration coverage across core primitives and native extensions.

use libremetaverse::rendering::{DetailLevel, SimpleMesh};
use libremetaverse::{Primitive, PrimitiveConstructionData};
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::RlvHarness;
use libremetaverse_rendering_mesh_foundry::MeshFoundry;
use libremetaverse_rendering_simple::SimpleRenderer;
use libremetaverse_types::{HoleType, PCode, PathCurve, ProfileCurve};
use metacrate_lsl_tools::{Lexer, Parser, generated_lexer, generated_parser};

fn world_primitive() -> Primitive {
    let mut primitive = Primitive::new_with_constructor().expect("Primitive constructor");
    let mut construction = PrimitiveConstructionData::new_with_constructor()
        .expect("PrimitiveConstructionData constructor");
    construction.p_code = PCode::Prim;
    construction.path_curve = PathCurve::Line;
    construction.set_profile_curve_with_property(ProfileCurve::Square);
    construction.set_profile_hole(HoleType::Same);
    construction.path_scale_x = 1.0;
    construction.path_scale_y = 1.0;
    construction.path_end = 1.0;
    construction.profile_end = 1.0;
    construction.path_revolutions = 1.0;
    primitive.prim_data = construction;
    primitive
}

fn mesh_signature(mesh: &SimpleMesh) -> u64 {
    let mut hash = 0xcbf2_9ce4_8422_2325_u64;
    for vertex in &mesh.vertices {
        for value in [
            vertex.position.x,
            vertex.position.y,
            vertex.position.z,
            vertex.normal.x,
            vertex.normal.y,
            vertex.normal.z,
            vertex.tex_coord.x,
            vertex.tex_coord.y,
        ] {
            hash = (hash ^ u64::from(value.to_bits())).wrapping_mul(0x0000_0100_0000_01b3);
        }
    }
    hash
}

#[test]
fn native_extensions_consume_core_models_and_preserve_service_state() {
    let primitive = world_primitive();
    let simple = SimpleRenderer::new()
        .expect("simple renderer")
        .generate_simple_mesh(primitive.clone(), DetailLevel::High)
        .expect("simple mesh");
    let foundry = MeshFoundry::new()
        .expect("mesh foundry")
        .generate_simple_mesh(primitive, DetailLevel::High)
        .expect("foundry mesh")
        .expect("legacy primitive is renderable");
    assert_eq!(simple.vertices.len(), foundry.vertices.len());
    assert_eq!(mesh_signature(&simple), mesh_signature(&foundry));
    assert_eq!(simple.indices, foundry.indices);

    let lexer = Lexer::new(generated_lexer().expect("generated lexer")).expect("lexer");
    let mut parser =
        Parser::new(generated_parser().expect("generated parser"), lexer).expect("parser");
    let symbol = parser
        .parse_with_string("Widget(value;):base(new Child[])".to_owned())
        .expect("generated class body");
    assert_eq!(
        (symbol.yyname(), symbol.yynum()),
        ("ClassBody".to_owned(), 19)
    );

    let rlv = RlvHarness::new().expect("RLV service");
    assert!(block_on(rlv.process("@fly=n")).expect("add restriction"));
    assert!(!rlv.service.permissions().can_fly().expect("permission"));
    assert!(block_on(rlv.process("@fly=y")).expect("remove restriction"));
    assert!(rlv.service.permissions().can_fly().expect("permission"));
}
