#pragma once

#include <cstdint>
#include <memory>  // Para shared_ptr
#include <string>  // Para string
#include <utility>
#include <vector>  // Para vector

#include "core/resources/resource_types.hpp"  // Para structs de recursos

namespace Resource {

    class Cache {
       public:
        enum class LoadingMode : std::uint8_t {
            EAGER,  // Carga todos los recursos en init() (comportamiento por defecto, producción)
            LAZY    // Sólo registra nombres; carga cada recurso la primera vez que se pide (desarrollo)
        };

        static void init(LoadingMode mode = LoadingMode::EAGER);  // Inicialización singleton
        static void destroy();                                    // Destrucción singleton
        static auto get() -> Cache*;                              // Acceso al singleton

        auto getSound(const std::string& name) -> Ja::Sound*;  // Getters de recursos
        auto getMusic(const std::string& name) -> Ja::Music*;
        auto getSurface(const std::string& name) -> std::shared_ptr<Surface>;
        auto getPalette(const std::string& name) -> Palette;
        auto getTextFile(const std::string& name) -> std::shared_ptr<Text::File>;
        auto getText(const std::string& name) -> std::shared_ptr<Text>;
        auto getAnimationData(const std::string& name) -> const AnimationResource&;
        auto getRoom(const std::string& name) -> std::shared_ptr<Room::Data>;
        auto getRooms() -> std::vector<RoomResource>&;

        void reload();  // Recarga todos los recursos
#ifdef _DEBUG
        void reloadRoom(const std::string& name);  // Recarga una habitación desde disco
#endif

       private:
        // Estructura para llevar la cuenta de los recursos cargados
        struct ResourceCount {
            int total{0};   // Número total de recursos
            int loaded{0};  // Número de recursos cargados

            // Añade una cantidad a los recursos cargados
            void add(int amount) {
                loaded += amount;
            }

            // Obtiene el porcentaje de recursos cargados
            [[nodiscard]] auto getPercentage() const -> float {
                return static_cast<float>(loaded) / static_cast<float>(total);
            }
        };

        // Métodos de carga de recursos
        void loadSounds();
        void loadMusics();
        void loadSurfaces();
        void loadPalettes();
        void loadTextFiles();
        void loadAnimations();
        void loadRooms();
        void createText();

        // Registro de stubs (modo lazy): sólo nombres, sin contenido
        void initLazyStubs();

        // Cargadores bajo demanda (modo lazy): cargan un recurso individual por nombre
        void loadSoundByName(const std::string& name);
        void loadMusicByName(const std::string& name);
        void loadSurfaceByName(const std::string& name);
        void loadPaletteByName(const std::string& name);
        void loadTextFileByName(const std::string& name);
        void loadAnimationByName(const std::string& name);
        void loadRoomByName(const std::string& name);

        // Métodos de limpieza
        void clear();
        void clearSounds();
        void clearMusics();

        // Métodos de gestión de carga
        void load();
        void calculateTotal();
        void renderProgress();
        static void checkEvents();
        void updateLoadingProgress(int steps = 5);

        // Helper para mensajes de error de carga
        static void logLoadError(const std::string& asset_type, const std::string& file_path, const std::exception& e);

        // Constructor y destructor
        explicit Cache(LoadingMode mode);
        ~Cache() = default;

        LoadingMode loading_mode_ = LoadingMode::EAGER;

        // Singleton instance
        static Cache* cache;

        // Variables miembro
        std::vector<SoundResource> sounds_;          // Vector con los sonidos
        std::vector<MusicResource> musics_;          // Vector con las musicas
        std::vector<SurfaceResource> surfaces_;      // Vector con las surfaces
        std::vector<ResourcePalette> palettes_;      // Vector con las paletas
        std::vector<TextFileResource> text_files_;   // Vector con los ficheros de texto
        std::vector<TextResource> texts_;            // Vector con los objetos de texto
        std::vector<AnimationResource> animations_;  // Vector con las animaciones
        std::vector<RoomResource> rooms_;            // Vector con las habitaciones

        ResourceCount count_{};               // Contador de recursos
        std::shared_ptr<Text> loading_text_;  // Texto para la pantalla de carga
    };

}  // namespace Resource
