///| Elastic easing functions with configurable amplitude and period

///|
/// Mathematical constants for elastic easing
let tau : Double = 2.0 * @math.PI

///|
let default_amplitude : Double = 1.0

///|
let default_period : Double = 0.3

///|
/// Helper function to compute the phase shift for elastic easing
fn compute_phase(amplitude : Double, period : Double) -> Double {
  let a = if amplitude > 1.0 { amplitude } else { 1.0 }
  let p = period / tau
  @math.asin(1.0 / a) * p
}

///|
/// Elastic ease-in function with configurable amplitude and period
/// @param t: time parameter (0.0 to 1.0)
/// @param amplitude: oscillation amplitude (default: 1.0)
/// @param period: oscillation period (default: 0.3)
pub fn elastic_in(
  t : Double,
  amplitude~ : Double = default_amplitude,
  period~ : Double = default_period,
) -> Double {
  let a = if amplitude > 1.0 { amplitude } else { 1.0 }
  let p = period / tau
  let s = compute_phase(amplitude, period)
  let t1 = t - 1.0
  a * tpmt(-t1) * @math.sin((s - t1) / p)
}

///|
/// Elastic ease-out function with configurable amplitude and period
/// @param t: time parameter (0.0 to 1.0)
/// @param amplitude: oscillation amplitude (default: 1.0)
/// @param period: oscillation period (default: 0.3)
pub fn elastic_out(
  t : Double,
  amplitude~ : Double = default_amplitude,
  period~ : Double = default_period,
) -> Double {
  let a = if amplitude > 1.0 { amplitude } else { 1.0 }
  let p = period / tau
  let s = compute_phase(amplitude, period)
  1.0 - a * tpmt(t) * @math.sin((t + s) / p)
}

///|
/// Elastic ease-in-out function with configurable amplitude and period
/// @param t: time parameter (0.0 to 1.0)
/// @param amplitude: oscillation amplitude (default: 1.0)
/// @param period: oscillation period (default: 0.3)
pub fn elastic_in_out(
  t : Double,
  amplitude~ : Double = default_amplitude,
  period~ : Double = default_period,
) -> Double {
  let a = if amplitude > 1.0 { amplitude } else { 1.0 }
  let p = period / tau
  let s = compute_phase(amplitude, period)
  let t2 = t * 2.0 - 1.0
  if t2 < 0.0 {
    a * tpmt(-t2) * @math.sin((s - t2) / p) / 2.0
  } else {
    (2.0 - a * tpmt(t2) * @math.sin((s + t2) / p)) / 2.0
  }
}