use lotus_script::{math::Vec2, time::delta};
use num_traits::Float;

mod piecewise_linear_function;

pub use piecewise_linear_function::*;

//---------------------------------

pub fn pt_to_px(pt: f32, dpi: f32) -> f32 {
    pt * dpi / 72.0
}

//---------------------------------

pub struct Polar {
    pub r: f32,
    pub theta: f32,
}

impl Polar {
    pub fn new(r: f32, theta: f32) -> Self {
        Self { r, theta }
    }

    pub fn rotate(&self, angle: f32) -> Self {
        Self {
            r: self.r,
            theta: self.theta + angle,
        }
    }

    pub fn scale(&self, factor: f32) -> Self {
        Self {
            r: self.r * factor,
            theta: self.theta,
        }
    }
}

impl From<Vec2> for Polar {
    fn from(v: Vec2) -> Self {
        Self {
            r: v.length(),
            theta: v.y.atan2(v.x).rem_euclid(std::f32::consts::TAU),
        }
    }
}

impl From<Polar> for Vec2 {
    fn from(p: Polar) -> Self {
        Vec2::new(p.r * p.theta.cos(), p.r * p.theta.sin())
    }
}

pub fn exponential_approach<T: Float>(old_value: T, exponent: T, target: T, delta: T) -> T {
    let factor = T::one() - (-delta * exponent).exp();
    old_value + factor * (target - old_value)
}

/// Performs exponential approach with different speeds for increasing and decreasing values.
///
/// This function applies exponential smoothing to approach a target value, but uses different
/// exponents depending on whether the target is above or below the current value. This is
/// useful for animations or smoothing operations where you want different response times
/// for upward vs downward movements.
///
/// # Arguments
///
/// * `value` - The current value
/// * `exponent_up` - The exponent to use when target > value (approaching upward)
/// * `exponent_down` - The exponent to use when target < value (approaching downward)
/// * `target` - The target value to approach
///
/// # Returns
///
/// The new value after applying the appropriate exponential approach
///
/// # Examples
///
/// ```
/// # use your_crate::helper::exponential_approach_two_speed;
/// // Smooth movement with faster upward motion
/// let current = 10.0;
/// let new_value = exponential_approach_two_speed(current, 0.1, 0.05, 20.0);
/// assert!(new_value > current && new_value < 20.0);
/// ```
#[must_use]
pub fn exponential_approach_two_speed(
    value: f32,
    exponent_up: f32,
    exponent_down: f32,
    target: f32,
) -> f32 {
    exponential_approach(
        value,
        if target > value {
            exponent_up
        } else {
            exponent_down
        },
        target,
        delta(),
    )
}
