pub mod blending;
pub mod rendering;
pub mod sampling;
pub mod skinning;
pub mod transform_hierarchy;

pub use blending::animation_blending_system;
pub use rendering::JointUploadSystem;
pub use sampling::animation_sampling_system;
pub use skinning::skinning_palette_system;
pub use transform_hierarchy::transform_hierarchy_system;

use archetype_ecs::prelude::*;
use archetype_ecs::system::{System, SystemAccess};
use std::any::TypeId;

/// ECS System wrapper for animation sampling
pub struct SamplingSystem;
impl System for SamplingSystem {
    fn name(&self) -> &'static str {
        "AnimationSamplingSystem"
    }
    fn access(&self) -> SystemAccess {
        let mut access = SystemAccess::empty();
        access
            .reads
            .push(TypeId::of::<crate::ecs::components::Animator>());
        access
            .writes
            .push(TypeId::of::<crate::ecs::components::Animator>());
        access.writes.push(TypeId::of::<LocalTransform>());
        access
            .reads
            .push(TypeId::of::<crate::ecs::resources::AnimationClipAssets>());
        access
            .reads
            .push(TypeId::of::<crate::ecs::resources::SkeletonAssets>());
        access.reads.push(TypeId::of::<Time>());
        access
    }
    fn run(&mut self, world: &mut World) -> Result<()> {
        let dt = world
            .resource::<Time>()
            .map(|t| t.delta_seconds())
            .unwrap_or(0.0);
        animation_sampling_system(world, dt);
        Ok(())
    }
}

/// ECS System wrapper for animation blending
pub struct BlendingSystem;
impl System for BlendingSystem {
    fn name(&self) -> &'static str {
        "AnimationBlendingSystem"
    }
    fn access(&self) -> SystemAccess {
        let mut access = SystemAccess::empty();
        access
            .reads
            .push(TypeId::of::<crate::ecs::components::Animator>());
        access
            .writes
            .push(TypeId::of::<crate::ecs::components::Animator>());
        access
            .reads
            .push(TypeId::of::<crate::ecs::components::AnimationBlend>());
        access
            .writes
            .push(TypeId::of::<crate::ecs::components::AnimationBlend>());
        access.writes.push(TypeId::of::<LocalTransform>());
        access.reads.push(TypeId::of::<Time>());
        access
    }
    fn run(&mut self, world: &mut World) -> Result<()> {
        let dt = world
            .resource::<Time>()
            .map(|t| t.delta_seconds())
            .unwrap_or(0.0);
        animation_blending_system(world, dt);
        Ok(())
    }
}

/// ECS System wrapper for skinning palette generation
pub struct SkinningSystem;
impl System for SkinningSystem {
    fn name(&self) -> &'static str {
        "SkinningSystem"
    }
    fn access(&self) -> SystemAccess {
        let mut access = SystemAccess::empty();
        access
            .reads
            .push(TypeId::of::<crate::ecs::components::SkinnedMesh>());
        access.reads.push(TypeId::of::<GlobalTransform>());
        access
            .writes
            .push(TypeId::of::<crate::ecs::components::JointPalette>());
        access
            .reads
            .push(TypeId::of::<crate::ecs::resources::SkeletonAssets>());
        access
    }
    fn run(&mut self, world: &mut World) -> Result<()> {
        skinning_palette_system(world);
        Ok(())
    }
}

/// ECS System wrapper for hierarchy propagation
pub struct HierarchySystem;
impl System for HierarchySystem {
    fn name(&self) -> &'static str {
        "TransformHierarchySystem"
    }
    fn access(&self) -> SystemAccess {
        let mut access = SystemAccess::empty();
        access.reads.push(TypeId::of::<LocalTransform>());
        access
            .reads
            .push(TypeId::of::<crate::ecs::components::Parent>());
        access.writes.push(TypeId::of::<GlobalTransform>());
        access
    }
    fn run(&mut self, world: &mut World) -> Result<()> {
        transform_hierarchy_system(world);
        Ok(())
    }
}
