#pragma once

#include <SDL3/SDL.h>

#include <memory>  // Para shared_ptr
#include <string>  // Para string
#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
        float speed{0.083F};            // Velocidad de la animación (segundos por frame)
        int loop{0};                    // Indica a que frame vuelve la animación al terminar. -1 para que no vuelva
        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)
    };

    // Métodos estáticos
    static auto loadAnimationsFromYAML(const std::string& file_path, std::shared_ptr<Surface>& surface, float& frame_width, float& frame_height) -> std::vector<AnimationData>;  // Carga las animaciones desde fichero YAML

    // 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 getIndex(const std::string& name) -> int;                                                                     // Obtiene el índice de la animación por nombre
    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:
    // Variables miembro
    std::vector<AnimationData> animations_;  // Vector con las diferentes animaciones
    int current_animation_{0};               // Animación activa
};