#pragma once

#include <memory>            // Para shared_ptr
#include <string>            // Para string
#include <vector>            // Para vector
#include "animated_sprite.h" // Para AnimationsFileBuffer
#include "text.h"            // Para TextFile, Text
#include "texture.h"         // Para Texture
#include "utils.h"           // Para DemoData

struct JA_Music_t;
struct JA_Sound_t;

// --- Estructuras para recursos individuales ---

// Sonido
struct ResourceSound
{
    std::string name;  // Nombre del sonido
    JA_Sound_t *sound; // Objeto con el sonido

    ResourceSound(const std::string &name, JA_Sound_t *sound)
        : name(name), sound(sound) {}
};

// Música
struct ResourceMusic
{
    std::string name;  // Nombre de la música
    JA_Music_t *music; // Objeto con la música

    ResourceMusic(const std::string &name, JA_Music_t *music)
        : name(name), music(music) {}
};

// Textura
struct ResourceTexture
{
    std::string name;                 // Nombre de la textura
    std::shared_ptr<Texture> texture; // Objeto con la textura

    ResourceTexture(const std::string &name, std::shared_ptr<Texture> texture)
        : name(name), texture(texture) {}
};

// Fichero de texto (fuente)
struct ResourceTextFile
{
    std::string name;                    // Nombre del fichero
    std::shared_ptr<TextFile> text_file; // Objeto con los descriptores de la fuente de texto

    ResourceTextFile(const std::string &name, std::shared_ptr<TextFile> text_file)
        : name(name), text_file(text_file) {}
};

// Objeto de texto
struct ResourceText
{
    std::string name;           // Nombre del objeto
    std::shared_ptr<Text> text; // Objeto

    ResourceText(const std::string &name, std::shared_ptr<Text> text)
        : name(name), text(text) {}
};

// Animación
struct ResourceAnimation
{
    std::string name;               // Nombre del fichero
    AnimationsFileBuffer animation; // Objeto con las animaciones

    ResourceAnimation(const std::string &name, const AnimationsFileBuffer &animation)
        : name(name), animation(animation) {}
};

// --- Clase Resource: gestiona todos los recursos del juego (singleton) ---
class Resource
{
public:
    // --- Métodos de singleton ---
    static void init();     // Inicializa el objeto Resource
    static void destroy();  // Libera el objeto Resource
    static Resource *get(); // Obtiene el puntero al objeto Resource

    // --- Métodos de acceso a recursos ---
    JA_Sound_t *getSound(const std::string &name);                  // Obtiene el sonido por nombre
    JA_Music_t *getMusic(const std::string &name);                  // Obtiene la música por nombre
    std::shared_ptr<Texture> getTexture(const std::string &name);   // Obtiene la textura por nombre
    std::shared_ptr<TextFile> getTextFile(const std::string &name); // Obtiene el fichero de texto por nombre
    std::shared_ptr<Text> getText(const std::string &name);         // Obtiene el objeto de texto por nombre
    AnimationsFileBuffer &getAnimation(const std::string &name);    // Obtiene la animación por nombre
    DemoData &getDemoData(int index);                               // Obtiene los datos de demo por índice

    // --- Recarga de recursos ---
    void reload();         // Recarga todos los recursos
    void reloadTextures(); // Recarga solo las texturas

private:
    // --- Singleton ---
    static Resource *resource_;

    // --- Vectores de recursos ---
    std::vector<ResourceSound> sounds_;         // Vector con los sonidos
    std::vector<ResourceMusic> musics_;         // Vector con las músicas
    std::vector<ResourceTexture> textures_;     // Vector con las texturas
    std::vector<ResourceTextFile> text_files_;  // Vector con los ficheros de texto
    std::vector<ResourceText> texts_;           // Vector con los objetos de texto
    std::vector<ResourceAnimation> animations_; // Vector con las animaciones
    std::vector<DemoData> demos_;               // Vector con los ficheros de datos para el modo demostración

    // --- Métodos internos de carga y gestión ---
    void loadSounds();     // Carga los sonidos
    void loadMusics();     // Carga las músicas
    void loadTextures();   // Carga las texturas
    void loadTextFiles();  // Carga los ficheros de texto
    void loadAnimations(); // Carga las animaciones
    void loadDemoData();   // Carga los datos para el modo demostración
    void addPalettes();    // Añade paletas a las texturas
    void createTextures(); // Crea las texturas a partir de los datos cargados
    void createText();     // Crea los objetos de texto
    void clear();          // Vacía todos los vectores de recursos
    void load();           // Carga todos los recursos
    void clearSounds();    // Vacía el vector de sonidos
    void clearMusics();    // Vacía el vector de músicas

    // --- Constructores y destructor privados (singleton) ---
    Resource();            // Constructor privado
    ~Resource() = default; // Destructor privado
};