#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Easing {
    Linear,
    EaseIn,
    EaseOut,
    EaseInOut,
}

pub struct Tween {
    start: f64,
    end: f64,
    duration: f64,
    elapsed: f64,
    easing: Easing,
    finished: bool,
}

impl Tween {
    pub fn new(start: f64, end: f64, duration: f64, easing: Easing) -> Self {
        Self {
            start,
            end,
            duration,
            elapsed: 0.0,
            easing,
            finished: false,
        }
    }

    pub fn tick(&mut self, delta: f64) -> f64 {
        self.elapsed += delta;
        if self.elapsed >= self.duration {
            self.elapsed = self.duration;
            self.finished = true;
        }
        self.value()
    }

    pub fn value(&self) -> f64 {
        if self.duration <= 0.0 {
            return self.end;
        }

        let t = (self.elapsed / self.duration).clamp(0.0, 1.0);
        let eased = match self.easing {
            Easing::Linear => t,
            Easing::EaseIn => t * t,
            Easing::EaseOut => 1.0 - (1.0 - t) * (1.0 - t),
            Easing::EaseInOut => {
                if t < 0.5 {
                    2.0 * t * t
                } else {
                    1.0 - (-2.0 * t + 2.0).powi(2) / 2.0
                }
            }
        };

        self.start + (self.end - self.start) * eased
    }

    pub fn finished(&self) -> bool {
        self.finished
    }

    pub fn reset(&mut self) {
        self.elapsed = 0.0;
        self.finished = false;
    }
}
