#pragma once

#include <SDL3/SDL_blendmode.h> // Para SDL_BlendMode
#include <SDL3/SDL_pixels.h>    // Para SDL_PixelFormat
#include <SDL3/SDL_rect.h>      // Para SDL_FPoint, SDL_FRect
#include <SDL3/SDL_render.h>    // Para SDL_Renderer, SDL_TextureAccess, SDL_Texture
#include <SDL3/SDL_stdinc.h>    // Para Uint8, Uint16, Uint32
#include <SDL3/SDL_surface.h>   // Para SDL_FlipMode
#include <memory>               // Para shared_ptr
#include <string>               // Para string
#include <vector>               // Para vector

struct Color;

// Definición de Surface para imágenes con paleta
struct Surface
{
    std::shared_ptr<Uint8[]> data;
    Uint16 w, h;

    // Constructor
    Surface(Uint16 width, Uint16 height, std::shared_ptr<Uint8[]> pixels)
        : data(pixels), w(width), h(height) {}
};

// Clase Texture: gestiona texturas, paletas y renderizado
class Texture
{
public:
    // --- Constructores y destructor ---
    explicit Texture(SDL_Renderer *renderer, const std::string &path = std::string());
    ~Texture();

    // --- Carga y creación ---
    bool loadFromFile(const std::string &path);                                                                                                         // Carga una imagen desde un fichero
    bool createBlank(int width, int height, SDL_PixelFormat format = SDL_PIXELFORMAT_RGBA8888, SDL_TextureAccess access = SDL_TEXTUREACCESS_STREAMING); // Crea una textura en blanco
    bool reLoad();                                                                                                                                      // Recarga la textura

    // --- Renderizado ---
    void render(int x, int y, SDL_FRect *clip = nullptr, float zoomW = 1, float zoomH = 1, double angle = 0.0, SDL_FPoint *center = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE); // Renderiza la textura en un punto específico
    void setAsRenderTarget(SDL_Renderer *renderer);                                                                                                                              // Establece la textura como objetivo de renderizado

    // --- Modificadores de color y blending ---
    void setColor(Uint8 red, Uint8 green, Uint8 blue); // Establece el color para la modulación
    void setColor(Color color);                        // Establece el color para la modulación
    void setBlendMode(SDL_BlendMode blending);         // Establece el blending
    void setAlpha(Uint8 alpha);                        // Establece el alpha para la modulación

    // --- Paletas ---
    void addPaletteFromFile(const std::string &path);           // Añade una paleta a la lista
    void setPaletteColor(int palette, int index, Uint32 color); // Establece un color de la paleta
    void setPalette(int palette);                               // Cambia la paleta de la textura

    // --- Getters ---
    int getWidth();               // Obtiene el ancho de la imagen
    int getHeight();              // Obtiene el alto de la imagen
    SDL_Texture *getSDLTexture(); // Obtiene la textura SDL
    SDL_Renderer *getRenderer();  // Obtiene el renderizador

private:
    // --- Objetos y punteros ---
    SDL_Renderer *renderer_;                     // Renderizador donde dibujar la textura
    SDL_Texture *texture_ = nullptr;             // La textura
    std::shared_ptr<Surface> surface_ = nullptr; // Surface para usar imágenes en formato gif con paleta

    // --- Variables ---
    std::string path_;                          // Ruta de la imagen de la textura
    int width_ = 0;                             // Ancho de la imagen
    int height_ = 0;                            // Alto de la imagen
    std::vector<std::vector<Uint32>> palettes_; // Vector con las diferentes paletas
    int current_palette_ = 0;                   // Índice de la paleta en uso

    // --- Métodos internos ---
    std::shared_ptr<Surface> loadSurface(const std::string &file_name);    // Crea una surface desde un fichero .gif
    void flipSurface();                                                    // Vuelca la surface en la textura
    std::vector<Uint32> loadPaletteFromFile(const std::string &file_name); // Carga una paleta desde un fichero
    void unloadTexture();                                                  // Libera la memoria de la textura
    void unloadSurface();                                                  // Libera la surface actual
};