use fyrox::{
    asset::manager::ResourceManager,
    core::{algebra::{Vector2, Vector3}, math::Rect, sstorage::ImmutableString},
    material::{shader::SamplerFallback, Material, MaterialResource, PropertyValue},
    resource::texture::Texture,
    scene::{
        base::BaseBuilder, collider::InteractionGroups, dim2::{
            collider::{ColliderBuilder, ColliderShape, CuboidShape},
            rectangle::RectangleBuilder,
            rigidbody::RigidBodyBuilder,
        }, graph::Graph, rigidbody::RigidBodyType, transform::TransformBuilder
    },
};
// /mnt/23154027-2dd3-43ea-93f1-02a8df7a3c5a/projects/fyrox/platformer/assets/data/tiles/
//

fn build_material(resource_manager: &ResourceManager, path: String) -> MaterialResource {
    let mut material = Material::standard_2d();
    material
        .set_property(
            &ImmutableString::new("diffuseTexture"),
            PropertyValue::Sampler {
                value: Some(resource_manager.request::<Texture>(path)),
                fallback: SamplerFallback::Normal,
            },
        )
        .unwrap();
    return MaterialResource::new_ok(Default::default(), material);
}

fn build_dynamic_block(
    graph: &mut Graph,
    x: f32,
    y: f32,
    scale: f32,
    material: MaterialResource,
    shape: ColliderShape,
    mass: f32,
) {
    let rb_transform = TransformBuilder::new()
        .with_local_position(Vector3::new(x, y, 0.0))
        .with_local_scale(Vector3::new(scale, scale, 1.0))
        .build();

    RigidBodyBuilder::new(
        BaseBuilder::new()
            .with_children(&[
                // Collider to prevent player from moving past boundary
                RectangleBuilder::new(BaseBuilder::new())
                    .with_material(material)
                    // Sprite is located in top left corner of sprite sheet
                    .with_uv_rect(Rect::new(0.0, 0.0, 1.0, 1.0))
                    .build(graph),
                ColliderBuilder::new(BaseBuilder::new())
                    .with_shape(shape)
                    .with_collision_groups(InteractionGroups::default())
                    .with_solver_groups(InteractionGroups::default())
                    .build(graph),
            ])
            // Optional, set name of tile
            .with_name(format!("Boundary ({x}, {y})",))
            // Set position of tile
            .with_local_transform(rb_transform),
    )
    .with_mass(mass)
    // Turn off gravity for tile
    .with_gravity_scale(1.)
    .with_lin_damping(2.0)
    // Set tile to be static and not rotate
    .with_rotation_locked(false)
    .with_body_type(RigidBodyType::Dynamic)
    .build(graph);
}

fn build_block(
    graph: &mut Graph,
    x: f32,
    y: f32,
    scale: f32,
    material: MaterialResource,
    shape: ColliderShape,
) {
    let rb_transform = TransformBuilder::new()
        .with_local_position(Vector3::new(x, y, 0.0))
        .with_local_scale(Vector3::new(scale, scale, 1.0))
        .build();

    RigidBodyBuilder::new(
        BaseBuilder::new()
            .with_children(&[
                // Collider to prevent player from moving past boundary
                RectangleBuilder::new(BaseBuilder::new())
                    .with_material(material)
                    // Sprite is located in top left corner of sprite sheet
                    .with_uv_rect(Rect::new(0.0, 0.0, 1.0, 1.0))
                    .build(graph),
                ColliderBuilder::new(BaseBuilder::new())
                    .with_shape(shape)
                    .build(graph),
            ])
            // Optional, set name of tile
            .with_name(format!("Boundary ({x}, {y})",))
            // Set position of tile
            .with_local_transform(rb_transform),
    )
    // Turn off gravity for tile
    .with_gravity_scale(0.)
    // Set tile to be static and not rotate
    .with_rotation_locked(true)
    .with_body_type(RigidBodyType::Static)
    .build(graph);
}

fn build_ground_block(resource_manager: &ResourceManager, graph: &mut Graph, x: f32, y: f32) {
    let shape = ColliderShape::Cuboid(CuboidShape::default());
    build_block(
        graph,
        x as f32,
        y,
        1.0,
        build_material(resource_manager, "assets/data/tiles/2.png".to_owned()),
        shape,
    )
}

fn build_center_block(resource_manager: &ResourceManager, graph: &mut Graph, x: f32, y: f32) {
    let shape = ColliderShape::Cuboid(CuboidShape::default());
    build_block(
        graph,
        x as f32,
        y,
        1.0,
        build_material(resource_manager, "assets/data/tiles/14.png".to_owned()),
        shape,
    )
}

fn build_left_block(resource_manager: &ResourceManager, graph: &mut Graph, x: f32, y: f32) {
    let shape = ColliderShape::Cuboid(CuboidShape::default());
    build_block(
        graph,
        x as f32,
        y,
        1.0,
        build_material(resource_manager, "assets/data/tiles/13.png".to_owned()),
        shape,
    )
}

fn build_right_block(resource_manager: &ResourceManager, graph: &mut Graph, x: f32, y: f32) {
    let shape = ColliderShape::Cuboid(CuboidShape::default());
    build_block(
        graph,
        x as f32,
        y,
        1.0,
        build_material(resource_manager, "assets/data/tiles/15.png".to_owned()),
        shape,
    )
}

fn build_tree_block(resource_manager: &ResourceManager, graph: &mut Graph, x: f32, y: f32) {
    let tree_shape = ColliderShape::Cuboid(CuboidShape {
        half_extents: Vector2::new(0.5, 1.5),
    });

    build_block(
        graph,
        x as f32,
        y + 1.5,
        2.0,
        build_material(
            resource_manager,
            "assets/data/objects/Tree_2.png".to_owned(),
        ),
        tree_shape,
    )
}

fn build_stone_block(resource_manager: &ResourceManager, graph: &mut Graph, x: f32, y: f32) {
    let shape = ColliderShape::Cuboid(CuboidShape::default());
    build_block(
        graph,
        x as f32,
        y + 0.7,
        1.0,
        build_material(
            resource_manager,
            "assets/data/objects/Stone.png".to_owned(),
        ),
        shape,
    )
}

// fn build_mushroom_block(resource_manager: &ResourceManager, graph: &mut Graph, x: f32, y: f32) {
//     let shape = ColliderShape::Cuboid(CuboidShape {
//         half_extents: Vector2::new(0.25, 0.25),
//     });
//     build_block(
//         graph,
//         x as f32,
//         y + 0.5,
//         0.5,
//         build_material(
//             resource_manager,
//             "assets/data/objects/Mushroom_2.png".to_owned(),
//         ),
//         shape,
//     )
// }

fn build_box_block(resource_manager: &ResourceManager, graph: &mut Graph, x: f32, y: f32) {
    let shape = ColliderShape::Cuboid(CuboidShape::default());
    build_dynamic_block(
        graph,
        x,
        y + 2.0,
        1.0,
        build_material(resource_manager, "assets/data/objects/Crate.png".to_owned()),
        shape,
        3.0,
    );
}

fn build_air_island_block(resource_manager: &ResourceManager, graph: &mut Graph, x: f32, y: f32) {
    build_left_block(resource_manager, graph, x + 0.5, y);
    build_center_block(resource_manager, graph, x, y);
    build_right_block(resource_manager, graph, x - 1.0, y);
}

pub fn build_map(graph: &mut Graph, resource_manager: &ResourceManager) {
    let bottom_y: f32 = -5.0;
    let left_x: i32 = -43;
    let right_x: i32 = 43;
    for x in left_x..right_x {
        build_ground_block(resource_manager, graph, x as f32, bottom_y);
    }
    build_stone_block(resource_manager, graph, 30.0, bottom_y);
    build_tree_block(resource_manager, graph, 35.0, bottom_y);
    build_stone_block(resource_manager, graph, -30.0, bottom_y);
    build_tree_block(resource_manager, graph, -35.0, bottom_y);
    build_box_block(resource_manager, graph, 10.0, bottom_y);

    build_air_island_block(resource_manager, graph, 15.0, bottom_y + 2.5);
    build_air_island_block(resource_manager, graph, 18.0, bottom_y + 4.0);
    build_air_island_block(resource_manager, graph, 21.0, bottom_y + 5.5);
    build_box_block(resource_manager, graph, 21.0, bottom_y+ 5.5);

    build_air_island_block(resource_manager, graph, -15.0, bottom_y + 2.5);
    build_air_island_block(resource_manager, graph, -18.0, bottom_y + 4.0);
    build_air_island_block(resource_manager, graph, -21.0, bottom_y + 5.5);

    // TODO: for  test collision
    // build_box_block(resource_manager, graph, 7.5, bottom_y+ 2.5);


}
