use anymotion::AnimationPipeline;
use anymotion::ecs::components::{JointPalette, Parent};
use anymotion::ecs::resources::{AnimationClipAssets, SkeletonAssets};
use anymotion::prelude::*;
use archetype_ecs::{GlobalTransform, World};
use glam::{Quat, Vec3};

#[test]
fn test_animation_pipeline_propagation() {
    let mut world = World::new();

    // 1. Setup Skeleton (Root -> Hips)
    let mut skeleton = Skeleton::new();
    skeleton.add_bone("Root".to_string(), None, glam::Mat4::IDENTITY);
    skeleton.add_bone("Hips".to_string(), Some(0), glam::Mat4::IDENTITY);

    // 2. Setup Animation (Animate Hips)
    let mut bone_tracks = std::collections::HashMap::new();
    let mut hips_track = anymotion::core::TransformTrack::new();
    hips_track.positions = vec![
        anymotion::core::Keyframe {
            time: 0.0,
            value: Vec3::ZERO,
            interpolation: anymotion::core::InterpolationMode::Linear,
        },
        anymotion::core::Keyframe {
            time: 1.0,
            value: Vec3::new(0.0, 1.0, 0.0),
            interpolation: anymotion::core::InterpolationMode::Linear,
        },
    ];
    bone_tracks.insert("Hips".to_string(), hips_track);
    let clip = AnimationClip::new("Test".to_string(), 1.0, bone_tracks).unwrap();

    // 3. Setup Assets
    let mut skeleton_assets = SkeletonAssets::new();
    let skele_handle = skeleton_assets.add(skeleton);

    let mut clip_assets = AnimationClipAssets::new();
    let clip_handle = clip_assets.add(clip);

    world.insert_resource(skeleton_assets);
    world.insert_resource(clip_assets);

    // 4. Spawn Entities
    // Root bone at (1,0,0)
    let root_entity = world.spawn((
        BoneJoint {
            bone_index: 0,
            skeleton: skele_handle,
        },
        Transform {
            position: Vec3::new(1.0, 0.0, 0.0),
            rotation: Quat::IDENTITY,
            scale: Vec3::ONE,
        },
        GlobalTransform::identity(),
    ));

    // Hips bone (child of Root) animated from (0,0,0) to (0,1,0)
    let hips_entity = world.spawn((
        BoneJoint {
            bone_index: 1,
            skeleton: skele_handle,
        },
        Parent {
            entity: root_entity,
        },
        Transform::default(),
        GlobalTransform::identity(),
    ));

    // Animated Mesh
    let mesh_entity = world.spawn((
        Animator::new(skele_handle, clip_handle),
        SkinnedMesh {
            skeleton: skele_handle,
            mesh_handle: 0,
            bone_entities: vec![root_entity, hips_entity],
            joint_offset: 0,
        },
        JointPalette::new(2),
        GlobalTransform::identity(),
    ));

    // 5. Run Pipeline (0.5s into animation)
    AnimationPipeline::update(&mut world, 0.5);

    // 6. Verify Results
    // Hips Local should be at (0, 0.5, 0)
    let hips_local = world.get_component::<Transform>(hips_entity).unwrap();
    assert!(
        (hips_local.position.y - 0.5).abs() < 0.001,
        "Hips Local should be sampled: {:?}",
        hips_local.position
    );

    // Hips Global should be RootGlobal * HipsLocal = (1, 0, 0) * (0, 0.5, 0) = (1, 0.5, 0)
    let hips_global = world.get_component::<GlobalTransform>(hips_entity).unwrap();
    assert!(
        (hips_global.position.x - 1.0).abs() < 0.001,
        "Hips Global X incorrect: {:?}",
        hips_global.position
    );
    assert!(
        (hips_global.position.y - 0.5).abs() < 0.001,
        "Hips Global Y incorrect: {:?}",
        hips_global.position
    );

    // JointPalette should be updated
    let palette = world.get_component::<JointPalette>(mesh_entity).unwrap();
    assert!(!palette.matrices.is_empty());
}
