#pragma once

/**
 * @file easing_functions.h
 * @brief Funciones de suavizado (easing) para animaciones
 *
 * Colección de funciones matemáticas para interpolar valores de forma suave.
 * Todas las funciones toman un parámetro t (0.0 - 1.0) y devuelven un valor interpolado.
 *
 * Uso típico:
 *   float progress = elapsed_time / total_duration;  // 0.0 a 1.0
 *   float eased = easeOutCubic(progress);
 *   float current_value = start + (end - start) * eased;
 *
 * Referencias:
 *   - https://easings.net/
 *   - Robert Penner's Easing Functions
 */

#include <cmath>

namespace Easing {

/**
 * @brief Interpolación lineal (sin suavizado)
 * @param t Progreso normalizado (0.0 - 1.0)
 * @return Valor interpolado linealmente
 *
 * Uso: Movimiento constante, sin aceleración
 */
inline float linear(float t) {
    return t;
}

/**
 * @brief Aceleración cuadrática (slow start)
 * @param t Progreso normalizado (0.0 - 1.0)
 * @return Valor interpolado con aceleración cuadrática
 *
 * Uso: Inicio lento que acelera
 */
inline float easeInQuad(float t) {
    return t * t;
}

/**
 * @brief Desaceleración cuadrática (slow end)
 * @param t Progreso normalizado (0.0 - 1.0)
 * @return Valor interpolado con desaceleración cuadrática
 *
 * Uso: Llegada suave, objetos que frenan
 */
inline float easeOutQuad(float t) {
    return t * (2.0f - t);
}

/**
 * @brief Aceleración y desaceleración cuadrática (slow start & end)
 * @param t Progreso normalizado (0.0 - 1.0)
 * @return Valor interpolado con aceleración y desaceleración
 *
 * Uso: Movimiento suave en ambos extremos
 */
inline float easeInOutQuad(float t) {
    return t < 0.5f ? 2.0f * t * t : -1.0f + (4.0f - 2.0f * t) * t;
}

/**
 * @brief Aceleración cúbica (slower start)
 * @param t Progreso normalizado (0.0 - 1.0)
 * @return Valor interpolado con aceleración cúbica
 *
 * Uso: Inicio muy lento, aceleración pronunciada
 */
inline float easeInCubic(float t) {
    return t * t * t;
}

/**
 * @brief Desaceleración cúbica (slower end)
 * @param t Progreso normalizado (0.0 - 1.0)
 * @return Valor interpolado con desaceleración cúbica
 *
 * Uso: Frenado suave y natural
 */
inline float easeOutCubic(float t) {
    float f = t - 1.0f;
    return f * f * f + 1.0f;
}

/**
 * @brief Aceleración y desaceleración cúbica
 * @param t Progreso normalizado (0.0 - 1.0)
 * @return Valor interpolado con curva cúbica
 *
 * Uso: Animaciones muy suaves en ambos extremos
 */
inline float easeInOutCubic(float t) {
    if (t < 0.5f) {
        return 4.0f * t * t * t;
    } else {
        float f = (2.0f * t - 2.0f);
        return 0.5f * f * f * f + 1.0f;
    }
}

/**
 * @brief Efecto elástico con rebote al final
 * @param t Progreso normalizado (0.0 - 1.0)
 * @return Valor interpolado con rebote elástico
 *
 * Uso: Elementos UI que "rebotan" al llegar, notificaciones
 * ⚠️ Puede sobrepasar el valor 1.0 temporalmente (overshoot)
 */
inline float easeOutElastic(float t) {
    if (t == 0.0f) return 0.0f;
    if (t == 1.0f) return 1.0f;

    constexpr float p = 0.3f;
    constexpr float s = p / 4.0f;

    return powf(2.0f, -10.0f * t) * sinf((t - s) * (2.0f * 3.14159265358979323846f) / p) + 1.0f;
}

/**
 * @brief Sobrepaso suave al final (back easing)
 * @param t Progreso normalizado (0.0 - 1.0)
 * @return Valor interpolado con sobrepaso
 *
 * Uso: Elementos que "se pasan" levemente y vuelven, efecto cartoon
 * ⚠️ Puede sobrepasar el valor 1.0 temporalmente (overshoot ~10%)
 */
inline float easeOutBack(float t) {
    constexpr float c1 = 1.70158f;
    constexpr float c3 = c1 + 1.0f;

    return 1.0f + c3 * powf(t - 1.0f, 3.0f) + c1 * powf(t - 1.0f, 2.0f);
}

/**
 * @brief Sobrepaso suave al inicio (back easing)
 * @param t Progreso normalizado (0.0 - 1.0)
 * @return Valor interpolado con retroceso inicial
 *
 * Uso: Elementos que "retroceden" antes de avanzar
 * ⚠️ Puede generar valores negativos al inicio (undershoot ~10%)
 */
inline float easeInBack(float t) {
    constexpr float c1 = 1.70158f;
    constexpr float c3 = c1 + 1.0f;

    return c3 * t * t * t - c1 * t * t;
}

/**
 * @brief Rebote físico al final (bounce effect)
 * @param t Progreso normalizado (0.0 - 1.0)
 * @return Valor interpolado con rebotes
 *
 * Uso: Objetos que caen y rebotan, físicas cartoon
 */
inline float easeOutBounce(float t) {
    constexpr float n1 = 7.5625f;
    constexpr float d1 = 2.75f;

    if (t < 1.0f / d1) {
        return n1 * t * t;
    } else if (t < 2.0f / d1) {
        t -= 1.5f / d1;
        return n1 * t * t + 0.75f;
    } else if (t < 2.5f / d1) {
        t -= 2.25f / d1;
        return n1 * t * t + 0.9375f;
    } else {
        t -= 2.625f / d1;
        return n1 * t * t + 0.984375f;
    }
}

/**
 * @brief Aceleración exponencial (muy dramática)
 * @param t Progreso normalizado (0.0 - 1.0)
 * @return Valor interpolado exponencialmente
 *
 * Uso: Efectos dramáticos, zoom in rápido
 */
inline float easeInExpo(float t) {
    return t == 0.0f ? 0.0f : powf(2.0f, 10.0f * (t - 1.0f));
}

/**
 * @brief Desaceleración exponencial (muy dramática)
 * @param t Progreso normalizado (0.0 - 1.0)
 * @return Valor interpolado exponencialmente
 *
 * Uso: Fade outs dramáticos, zoom out rápido
 */
inline float easeOutExpo(float t) {
    return t == 1.0f ? 1.0f : 1.0f - powf(2.0f, -10.0f * t);
}

/**
 * @brief Curva circular (cuarto de círculo)
 * @param t Progreso normalizado (0.0 - 1.0)
 * @return Valor interpolado con curva circular
 *
 * Uso: Movimientos muy suaves y naturales
 */
inline float easeOutCirc(float t) {
    return sqrtf(1.0f - powf(t - 1.0f, 2.0f));
}

} // namespace Easing
