#include "game/ui/ui_message.hpp"

#include <algorithm>
#include <cmath>  // Para pow
#include <utility>

#include "core/rendering/text.hpp"  // Para Text::CENTER, Text::COLOR, Text

// Constructor: inicializa el renderizador, el texto y el color del mensaje
UIMessage::UIMessage(std::shared_ptr<Text> text_renderer, std::string message_text, const Color& color)
    : text_renderer_(std::move(text_renderer)),
      text_(std::move(message_text)),
      color_(color) {}

// Muestra el mensaje en la posición base_x, base_y con animación de entrada desde arriba
void UIMessage::show() {
    if (visible_ && target_y_ == 0.0F) {
        return;  // Ya está visible y quieto
    }

    start_y_ = DESP;   // Empieza 8 píxeles arriba de la posición base
    target_y_ = 0.0F;  // La posición final es la base
    y_offset_ = start_y_;
    animation_timer_ = 0.0F;
    animating_ = true;
    visible_ = true;
}

// Oculta el mensaje con animación de salida hacia arriba
void UIMessage::hide() {
    if (!visible_) {
        return;
    }

    start_y_ = y_offset_;  // Comienza desde la posición actual
    target_y_ = DESP;      // Termina 8 píxeles arriba de la base
    animation_timer_ = 0.0F;
    animating_ = true;
}

// Actualiza el estado de la animación (debe llamarse cada frame)
void UIMessage::update(float delta_time) {
    if (animating_) {
        updateAnimation(delta_time);
    }
}

// Interpola la posición vertical del mensaje usando ease out cubic
void UIMessage::updateAnimation(float delta_time) {
    animation_timer_ += delta_time;
    float t = animation_timer_ / ANIMATION_DURATION_S;

    // Clamp t entre 0 y 1
    t = std::min(t, 1.0F);

    if (target_y_ > start_y_) {
        // Animación de entrada (ease out cubic)
        t = 1 - pow(1 - t, 3);
    } else {
        // Animación de salida (ease in cubic)
        t = pow(t, 3);
    }

    y_offset_ = start_y_ + ((target_y_ - start_y_) * t);

    if (animation_timer_ >= ANIMATION_DURATION_S) {
        y_offset_ = target_y_;
        animating_ = false;
        animation_timer_ = 0.0F;  // Reset timer
        if (target_y_ < 0.0F) {
            visible_ = false;
        }
    }
}

// Dibuja el mensaje en pantalla si está visible
void UIMessage::render() {
    if (visible_) {
        text_renderer_->writeDX(
            Text::COLOR | Text::CENTER,
            base_x_,
            base_y_ + y_offset_,
            text_,
            -2,
            color_);
    }
}

// Devuelve true si el mensaje está visible actualmente
auto UIMessage::isVisible() const -> bool {
    return visible_;
}

// Permite actualizar la posición del mensaje (por ejemplo, si el menú se mueve)
void UIMessage::setPosition(float new_base_x, float new_base_y) {
    base_x_ = new_base_x;
    base_y_ = new_base_y;
}