#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
#include "texture.h"         // Para Texture
#include "utils.h"           // Para DemoData
struct JA_Music_t;
struct JA_Sound_t;

// Estructura para almacenar ficheros de sonido y su nombre
struct ResourceSound
{
    std::string name;  // Nombre del sonido
    JA_Sound_t *sound; // Objeto con el sonido

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

// Estructura para almacenar ficheros musicales y su nombre
struct ResourceMusic
{
    std::string name;  // Nombre de la musica
    JA_Music_t *music; // Objeto con la música

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

// Estructura para almacenar objetos Texture y su nombre
struct ResourceTexture
{
    std::string name;                 // Nombre de la textura
    std::shared_ptr<Texture> texture; // Objeto con la textura

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

// Estructura para almacenar ficheros TextFile y su nombre
struct ResourceTextFile
{
    std::string name;                    // Nombre del fichero
    std::shared_ptr<TextFile> text_file; // Objeto con los descriptores de la fuente de texto

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

// Estructura para almacenar ficheros animaciones y su nombre
struct ResourceAnimation
{
    std::string name;               // Nombre del fichero
    AnimationsFileBuffer animation; // Objeto con las animaciones

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

class Resource
{
private:
    // [SINGLETON] Objeto resource privado para Don Melitón
    static Resource *resource_;

    std::vector<ResourceSound> sounds_;         // Vector con los sonidos
    std::vector<ResourceMusic> musics_;         // Vector con las musicas
    std::vector<ResourceTexture> textures_;     // Vector con las musicas
    std::vector<ResourceTextFile> text_files_;  // Vector con los ficheros 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

    // Carga los sonidos
    void loadSounds();

    // Carga las musicas
    void loadMusics();

    // Carga las texturas
    void loadTextures();

    // Carga los ficheros de texto
    void loadTextFiles();

    // Carga las animaciones
    void loadAnimations();

    // Carga los datos para el modo demostración
    void loadDemoData();

    // Añade paletas a las texturas
    void addPalettes();

    // Crea texturas
    void createTextures();

    // [SINGLETON] Ahora el constructor y el destructor son privados, para no poder crear objetos resource desde fuera

    // Constructor
    Resource();

    // Destructor
    ~Resource() = default;

public:
    // [SINGLETON] Crearemos el objeto resource con esta función estática
    static void init();

    // [SINGLETON] Destruiremos el objeto resource con esta función estática
    static void destroy();

    // [SINGLETON] Con este método obtenemos el objeto resource y podemos trabajar con él
    static Resource *get();

    // Obtiene el sonido a partir de un nombre
    JA_Sound_t *getSound(const std::string &name);

    // Obtiene la música a partir de un nombre
    JA_Music_t *getMusic(const std::string &name);

    // Obtiene la textura a partir de un nombre
    std::shared_ptr<Texture> getTexture(const std::string &name);

    // Obtiene el fichero de texto a partir de un nombre
    std::shared_ptr<TextFile> getTextFile(const std::string &name);

    // Obtiene la animación a partir de un nombre
    AnimationsFileBuffer &getAnimation(const std::string &name);

    // Obtiene el fichero con los datos para el modo demostración a partir de un çindice
    DemoData &getDemoData(int index);
};