#pragma once

#include <SDL2/SDL_render.h> // Para SDL_Renderer
#include <SDL2/SDL_stdinc.h> // Para Uint8, Uint32
#include <array>
#include <memory>
#include <string>

struct SurfaceData
{
    Uint8 *data;
    Uint16 width;
    Uint16 height;

    // Constructor por defecto
    SurfaceData() : data(nullptr), width(0), height(0) {}

    // Constructor que inicializa dimensiones y asigna memoria
    SurfaceData(Uint16 w, Uint16 h)
        : data(new Uint8[w * h]()), width(w), height(h) {}

    // Constructor para inicializar directamente con datos
    SurfaceData(Uint16 w, Uint16 h, Uint8 *pixels)
        : data(pixels), width(w), height(h) {}

    // Destructor para liberar memoria
    ~SurfaceData() { delete[] data; }

    // Evita copias accidentales (opcional para mayor seguridad)
    SurfaceData(const SurfaceData &) = delete;
    SurfaceData &operator=(const SurfaceData &) = delete;

    // Permite movimiento para evitar copias costosas
    SurfaceData(SurfaceData &&other) noexcept
        : data(other.data), width(other.width), height(other.height)
    {
        other.data = nullptr;
        other.width = 0;
        other.height = 0;
    }

    SurfaceData &operator=(SurfaceData &&other) noexcept
    {
        if (this != &other)
        {
            delete[] data;

            data = other.data;
            width = other.width;
            height = other.height;

            other.data = nullptr;
            other.width = 0;
            other.height = 0;
        }
        return *this;
    }
};

class Surface
{
private:
    std::shared_ptr<SurfaceData> surface_dest_;
    std::shared_ptr<SurfaceData> surface_;
    std::array<Uint32, 256> palette_;
    int transparent_color_;

    // Pone un pixel en la superficie de destino
    void putPixel(int x, int y, Uint8 color);

    // Obtiene el color de un pixel de la superficie de origen
    Uint8 getPixel(int x, int y);

public:
    // Constructor
    Surface(std::shared_ptr<SurfaceData> surface_dest, int w, int h);
    Surface(std::shared_ptr<SurfaceData> surface_dest, const std::string &file_path);

    // Destructor
    ~Surface();

    // Carga una superficie desde un archivo
    SurfaceData loadSurface(const std::string &file_path);

    // Carga una paleta desde un archivo
    void loadPalette(const std::string &file_path);

    // Copia una región de la superficie de origen a la de destino
    void render(int dx, int dy, int sx, int sy, int w, int h);

    // Establece un color en la paleta
    void setColor(int index, Uint32 color);

    // Limpia la superficie de destino con un color
    void clear(std::shared_ptr<SurfaceData> surface, Uint8 color);

    // Vuelca la superficie a una textura
    void copyToTexture(SDL_Renderer *renderer, SDL_Texture *texture);

    // Realiza un efecto de fundido en la paleta
    bool fadePalette();

    // Getters
    std::shared_ptr<SurfaceData> getSurface() const { return surface_; }
    // std::shared_ptr<SurfaceData> getSurfaceDest() const { return surface_dest_; }
    // std::array<Uint32, 256> getPalette() const { return palette_; }
    int getTransparentColor() const { return transparent_color_; }
};
