#pragma once

#include <SDL3/SDL.h>  // Para SDL_FRect, SDL_FPoint

#include <cstddef>  // Para size_t
#include <memory>   // Para shared_ptr
#include <utility>
#include <vector>  // Para vector

class Texture;

// --- Clase Sprite: representa un objeto gráfico básico con posición, tamaño y textura ---
class Sprite {
   public:
    // --- Constructores y destructor ---
    Sprite(std::shared_ptr<Texture> texture, float pos_x, float pos_y, float width, float height);
    Sprite(std::shared_ptr<Texture> texture, SDL_FRect rect);
    explicit Sprite(std::shared_ptr<Texture> texture);
    virtual ~Sprite() = default;

    // --- Renderizado y control ---
    virtual void render();  // Muestra el sprite por pantalla
    virtual void clear();   // Reinicia las variables a cero

    // --- Getters de posición y tamaño ---
    [[nodiscard]] auto getX() const -> float { return pos_.x; }
    [[nodiscard]] auto getY() const -> float { return pos_.y; }
    [[nodiscard]] auto getWidth() const -> float { return pos_.w; }
    [[nodiscard]] auto getHeight() const -> float { return pos_.h; }
    [[nodiscard]] auto getPosition() const -> SDL_FRect { return pos_; }
    auto getRect() -> SDL_FRect& { return pos_; }

    // --- Setters de posición y tamaño ---
    void setX(float pos_x) { pos_.x = pos_x; }
    void setY(float pos_y) { pos_.y = pos_y; }
    void setWidth(float width) { pos_.w = width; }
    void setHeight(float height) { pos_.h = height; }
    void setPosition(float pos_x, float pos_y);
    void setPosition(SDL_FPoint point);
    void setPosition(SDL_FRect rect) { pos_ = rect; }

    // --- Zoom ---
    void setZoom(float zoom) { zoom_ = zoom; }

    // --- Modificación de posición ---
    void incX(float value) { pos_.x += value; }
    void incY(float value) { pos_.y += value; }

    // --- Sprite clip ---
    [[nodiscard]] auto getSpriteClip() const -> SDL_FRect { return sprite_clip_; }
    void setSpriteClip(SDL_FRect rect) { sprite_clip_ = rect; }
    void setSpriteClip(float pos_x, float pos_y, float width, float height) { sprite_clip_ = SDL_FRect{.x = pos_x, .y = pos_y, .w = width, .h = height}; }

    // --- Textura ---
    [[nodiscard]] auto getTexture() const -> std::shared_ptr<Texture> { return textures_.at(texture_index_); }
    void setTexture(std::shared_ptr<Texture> texture) { textures_.at(texture_index_) = std::move(texture); }
    void addTexture(const std::shared_ptr<Texture>& texture) { textures_.push_back(texture); }
    auto setActiveTexture(size_t index) -> bool;                                       // Cambia la textura activa por índice
    [[nodiscard]] auto getActiveTexture() const -> size_t { return texture_index_; }   // Alias para getActiveTextureIndex
    [[nodiscard]] auto getTextureCount() const -> size_t { return textures_.size(); }  // Obtiene el número total de texturas

   protected:
    // --- Métodos internos ---
    auto getTextureRef() -> std::shared_ptr<Texture>& { return textures_.at(texture_index_); }  // Obtiene referencia a la textura activa

    // --- Variables internas ---
    std::vector<std::shared_ptr<Texture>> textures_;  // Lista de texturas
    size_t texture_index_ = 0;                        // Índice de la textura activa
    SDL_FRect pos_;                                   // Posición y tamaño donde dibujar el sprite
    SDL_FRect sprite_clip_;                           // Rectángulo de origen de la textura que se dibujará en pantalla
    double zoom_ = 1.0F;                              // Zoom aplicado a la textura
};