use crate::core::clip::AnimationClip;
use glam::{Quat, Vec3};
use std::collections::HashMap;

/// Playback state for an animation on an entity
#[derive(Debug, Clone)]
pub struct AnimationPlayer {
    /// Time elapsed since the start of the animation
    pub time: f32,
    /// Playback speed multiplier (1.0 is normal speed)
    pub speed: f32,
    /// Whether the animation should loop
    pub is_looping: bool,
    /// Whether the animation is currently playing
    pub is_playing: bool,
}

impl AnimationPlayer {
    pub fn new() -> Self {
        Self {
            time: 0.0,
            speed: 1.0,
            is_looping: true,
            is_playing: true,
        }
    }

    /// Advance the animation time
    pub fn update(&mut self, dt: f32) {
        if !self.is_playing {
            return;
        }

        self.time += dt * self.speed;
    }

    /// Advance time and apply looping/clamping based on duration
    pub fn update_constrained(&mut self, dt: f32, duration: f32) {
        if !self.is_playing {
            return;
        }

        self.time += dt * self.speed;

        if self.is_looping {
            self.time = self.time.rem_euclid(duration);
        } else {
            self.time = self.time.min(duration);
        }
    }

    /// Sample the given clip at the current time
    /// Returns a map of bone name to (pos, rot, scale)
    pub fn sample(&self, clip: &AnimationClip) -> HashMap<String, (Vec3, Quat, Vec3)> {
        let mut transforms = HashMap::new();

        let wrapped_time = if self.is_looping {
            self.time.rem_euclid(clip.duration)
        } else {
            self.time.min(clip.duration)
        };

        for (bone_name, track) in &clip.bone_tracks {
            transforms.insert(bone_name.clone(), track.sample(wrapped_time));
        }

        transforms
    }

    /// Reset animation to the beginning
    pub fn reset(&mut self) {
        self.time = 0.0;
    }

    /// Stop playback
    pub fn pause(&mut self) {
        self.is_playing = false;
    }

    /// Resume playback
    pub fn resume(&mut self) {
        self.is_playing = true;
    }
}

impl Default for AnimationPlayer {
    fn default() -> Self {
        Self::new()
    }
}
