#pragma once

#include <cstdint>     // Para uint8_t
#include <functional>  // Para std::function
#include <memory>      // Para shared_ptr
#include <string>      // Para string
#include <utility>
#include <vector>  // Para vector

#include "core/resources/resource_list.hpp"   // Para List::Type
#include "core/resources/resource_types.hpp"  // Para structs de recursos

namespace Resource {

    class Cache {
       public:
        static void init();           // 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>&;

        // --- Incremental loading (Director drives this from iterate()) ---
        void beginLoad();                      // Prepara el estado del loader incremental
        auto loadStep(int budget_ms) -> bool;  // Carga assets durante budget_ms; devuelve true si ha terminado
        void renderProgress();                 // Dibuja la barra de progreso (usada por BootLoader)
        [[nodiscard]] auto isLoadDone() const -> bool;

        void reload();  // Recarga todos los recursos (síncrono, usado en hot-reload de debug)
#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);
            }
        };

        // Etapas del loader incremental
        enum class LoadStage : std::uint8_t {
            SOUNDS,
            MUSICS,
            SURFACES,
            SURFACES_POST,  // Ajuste de transparent colors tras cargar todas las surfaces
            PALETTES,
            TEXT_FILES,
            ANIMATIONS,
            ROOMS,
            TEXTS,
            DONE
        };

        // Métodos de carga de recursos (bucle completo, usados por reload() síncrono)
        void loadSounds();
        void loadMusics();
        void loadSurfaces();
        void loadPalettes();
        void loadTextFiles();
        void loadAnimations();
        void loadRooms();
        void createText();

        // Helpers incrementales: cargan un único asset de la categoría correspondiente
        void loadOneSound(size_t index);
        void loadOneMusic(size_t index);
        void loadOneSurface(size_t index);
        void finalizeSurfaces();  // Ajuste de transparent colors tras cargar surfaces
        void loadOnePalette(size_t index);
        void loadOneTextFile(size_t index);
        void loadOneAnimation(size_t index);
        void loadOneRoom(size_t index);
        void createOneText(size_t index);

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

        // Métodos de gestión de carga
        void load();  // Carga completa síncrona (usado solo por reload())
        void calculateTotal();
        void updateLoadingProgress();
        void setCurrentLoading(const std::string& name);  // Desa el nom del recurs en curs

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

        // Helper d'iteració per a una etapa que recorre una llista de recursos.
        // Crida `load_fn(i)` per a cada element i, en exhaurir-se, transiciona a `next`.
        void stepEachInList(List::Type type, const char* header, const std::function<void()>& clear_fn, LoadStage next, const std::function<void(size_t)>& load_fn);
        void stepTexts();  // Etapa especial: no usa List, itera sobre TEXT_COUNT fonts fixes.

        // Constructor y destructor
        Cache();
        ~Cache() = default;

        // 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
        std::string current_loading_name_;    // Nom del recurs que s'està a punt de carregar

        // Estado del loader incremental
        LoadStage stage_{LoadStage::DONE};  // Arranca en DONE hasta que beginLoad() lo cambie
        size_t stage_index_{0};             // Cursor dentro de la categoría actual
    };

}  // namespace Resource
