#pragma once

#include <SDL3/SDL.h>  // Para Uint8, SDL_Renderer, Uint16, SDL_FlipMode, SDL_PixelFormat, SDL_TextureAccess, SDL_Texture, Uint32, SDL_BlendMode, SDL_FPoint, SDL_FRect

#include <array>    // Para array
#include <cstddef>  // Para size_t
#include <memory>   // Para shared_ptr
#include <string>   // Para string, basic_string
#include <utility>
#include <vector>  // Para vector

struct Color;

// Alias
using Palette = std::array<Uint32, 256>;

// Definición de Surface para imágenes con paleta
struct Surface {
    std::shared_ptr<Uint8[]> data;  // NOLINT(modernize-avoid-c-arrays)
    Uint16 w, h;

    // Constructor
    Surface(Uint16 width, Uint16 height, std::shared_ptr<Uint8[]> pixels)  // NOLINT(modernize-avoid-c-arrays)
        : data(std::move(pixels)),
          w(width),
          h(height) {}
};

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

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

    // --- Renderizado ---
    void render(int x, int y, SDL_FRect* clip = nullptr, float horizontal_zoom = 1, float vertical_zoom = 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 addPaletteFromGifFile(const std::string& path);         // Añade una paleta a la lista
    void addPaletteFromPalFile(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(size_t palette);                             // Cambia la paleta de la textura

    // --- Getters ---
    [[nodiscard]] auto getWidth() const -> int;   // Obtiene el ancho de la imagen
    [[nodiscard]] auto getHeight() const -> int;  // Obtiene el alto de la imagen
    auto getSDLTexture() -> SDL_Texture*;         // Obtiene la textura SDL
    auto getRenderer() -> SDL_Renderer*;          // 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<Palette> palettes_;  // Vector con las diferentes paletas
    int current_palette_ = 0;        // Índice de la paleta en uso

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