use crate::coords::{Cube, Axial};

pub trait LinearInterpolation {
  fn lerp(&self, to: &Self, t: f32) -> Self;
}

impl LinearInterpolation for f32 {
  fn lerp(&self, to: &f32, t: f32) -> f32 {
    self + (to - self) * t
  }
}

impl LinearInterpolation for Cube {
  /// ```
  /// use bestagon::{coords::Cube, lerp::LinearInterpolation};
  /// assert_eq!(Cube(0, 0, 0).lerp(&Cube(5, -4, -1), 0.00), Cube(0, 0, 0));
  /// assert_eq!(Cube(0, 0, 0).lerp(&Cube(5, -4, -1), 0.25), Cube(1, -1, 0));
  /// assert_eq!(Cube(0, 0, 0).lerp(&Cube(5, -4, -1), 0.49), Cube(2, -2, 0));
  /// assert_eq!(Cube(0, 0, 0).lerp(&Cube(5, -4, -1), 0.51), Cube(3, -2, -1));
  /// assert_eq!(Cube(0, 0, 0).lerp(&Cube(5, -4, -1), 0.75), Cube(4, -3, -1));
  /// assert_eq!(Cube(0, 0, 0).lerp(&Cube(5, -4, -1), 1.00), Cube(5, -4, -1));
  /// ```
  fn lerp(&self, to: &Cube, t: f32) -> Cube {
    let x = (self.0 as f32).lerp(&(to.0 as f32), t).round() as i8;
    let y = (self.1 as f32).lerp(&(to.1 as f32), t).round() as i8;
    Cube(x, y, -x - y)
  }
}

impl LinearInterpolation for Axial {
  /// ```
  /// use bestagon::{coords::Axial, lerp::LinearInterpolation};
  /// assert_eq!(Axial(0, 0).lerp(&Axial(5, -4), 0.00), Axial(0, 0));
  /// assert_eq!(Axial(0, 0).lerp(&Axial(5, -4), 0.25), Axial(1, -1));
  /// assert_eq!(Axial(0, 0).lerp(&Axial(5, -4), 0.49), Axial(2, -2));
  /// assert_eq!(Axial(0, 0).lerp(&Axial(5, -4), 0.51), Axial(3, -2));
  /// assert_eq!(Axial(0, 0).lerp(&Axial(5, -4), 0.75), Axial(4, -3));
  /// assert_eq!(Axial(0, 0).lerp(&Axial(5, -4), 1.00), Axial(5, -4));
  /// ```
  fn lerp(&self, to: &Axial, t: f32) -> Axial {
    let x = (self.0 as f32).lerp(&(to.0 as f32), t).round() as i8;
    let y = (self.1 as f32).lerp(&(to.1 as f32), t).round() as i8;
    Axial(x, y)
  }
}
