#pragma once

#include <SDL3/SDL.h>

#include <memory>         // Para shared_ptr
#include <string>         // Para string
#include <unordered_map>  // Para unordered_map
#include <utility>
#include <vector>  // Para vector

#include "core/rendering/sprite/moving_sprite.hpp"  // Para SMovingSprite
#include "core/resources/resource_types.hpp"        // Para AnimationResource

class Surface;

class AnimatedSprite : public MovingSprite {
   public:
    using Animations = std::vector<std::string>;  // Tipo para lista de animaciones

    // Estructura pública de datos de animación
    struct AnimationData {
        std::string name;               // Nombre de la animacion
        std::vector<SDL_FRect> frames;  // Cada uno de los frames que componen la animación
        std::vector<float> speeds;      // Duración de cada frame en segundos (vacío = animación estática)
        int loop_from{-1};              // Frame al que volver al acabar (-1 = sin loop, congela en el último)
        bool completed{false};          // Indica si ha finalizado la animación
        int current_frame{0};           // Frame actual
        float accumulated_time{0.0F};   // Tiempo acumulado para las animaciones (time-based)
    };

    // Constructores
    explicit AnimatedSprite(const AnimationResource& cached_data);  // Constructor con datos pre-cargados del cache

    ~AnimatedSprite() override = default;  // Destructor

    void update(float delta_time) override;  // Actualiza las variables del objeto (time-based)

    // Consultas de estado
    auto animationIsCompleted() -> bool;                                                                               // Comprueba si ha terminado la animación
    auto getCurrentAnimationSize() -> int { return static_cast<int>(animations_[current_animation_].frames.size()); }  // Número de frames de la animación actual

    // Modificadores de animación
    void setCurrentAnimation(const std::string& name = "default");  // Establece la animación actual por nombre
    void setCurrentAnimation(int index = 0);                        // Establece la animación actual por índice
    void resetAnimation();                                          // Reinicia la animación
    void setCurrentAnimationFrame(int num);                         // Establece el frame actual de la animación
    void animate(float delta_time);                                 // Calcula el frame correspondiente a la animación actual (time-based)

   protected:
    // Constructor per a ús de subclasses que gestionen la surface directament (sense YAML)
    AnimatedSprite(std::shared_ptr<Surface> surface, SDL_FRect pos);

   private:
    void buildNameIndex();  // Construye el mapa nombre→índice

    // Variables miembro
    std::vector<AnimationData> animations_;                 // Vector con las diferentes animaciones
    std::unordered_map<std::string, int> animation_index_;  // Mapa nombre→índice para búsqueda O(1)
    int current_animation_{0};                              // Animación activa
};