#pragma once

#include <SDL3/SDL.h>  // Para SDL_FRect

#include <cstddef>  // Para size_t
#include <memory>   // Para shared_ptr
#include <string>   // Para string
#include <utility>  // Para move
#include <vector>   // Para vector

#include "animated_sprite.h"  // Para AnimationsFileBuffer
#include "text.h"             // Para Text, TextFile
#include "texture.h"          // Para Texture
#include "utils.h"            // Para DemoData

struct JA_Music_t;
struct JA_Sound_t;

// --- 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 auto get() -> Resource *;  // Obtiene el puntero al objeto Resource

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

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

    private:
        // --- Estructuras para recursos individuales ---
        struct ResourceSound {
                std::string name;   // Nombre del sonido
                JA_Sound_t *sound;  // Objeto con el sonido

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

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

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

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

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

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

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

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

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

        struct ResourceAnimation {
                std::string name;                // Nombre de la animación
                AnimationsFileBuffer animation;  // Objeto con las animaciones

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

        // --- Estructura para el progreso de carga ---
        struct ResourceCount {
                size_t total;   // Número total de recursos
                size_t loaded;  // Número de recursos cargados

                ResourceCount() : total(0), loaded(0) {}
                ResourceCount(size_t total) : total(total), loaded(0) {}

                void add(size_t amount) { loaded += amount; }
                void increase() { loaded++; }
                [[nodiscard]] auto getPercentage() const -> float {
                    return total > 0 ? static_cast<float>(loaded) / static_cast<float>(total) : 0.0F;
                }
        };

        // --- 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

        // --- Progreso de carga ---
        ResourceCount loading_count_;         // Contador de recursos cargados
        std::shared_ptr<Text> loading_text_;  // Texto para escribir en pantalla
        std::string loading_resource_name_;   // Nombre del recurso que se está cargando
        SDL_FRect loading_wired_rect_;
        SDL_FRect loading_full_rect_;

        // --- 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

        // --- Métodos internos para gestionar el progreso ---
        void calculateTotalResources();                // Calcula el número de recursos para cargar
        void renderProgress();                         // Muestra el progreso de carga
        static void checkEvents();                     // Comprueba los eventos durante la carga
        void updateLoadingProgress(std::string name);  // Actualiza el progreso de carga
        void initProgressBar();                        // Inicializa los rectangulos que definen la barra de progreso
        void updateProgressBar();                      // Actualiza la barra de estado

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

        // --- Instancia singleton ---
        static Resource *instance;  // Instancia única de Resource
};