#pragma once

#include <SDL3/SDL.h>

#include <cstddef>
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include <vector>

#include "core/resources/resource_list.hpp"
#include "core/resources/resource_types.hpp"

namespace Resource {

    // Cache singleton: precarga + decode dels assets llistats al
    // `Resource::List`. Implementa carrega incremental amb pressupost
    // de temps per frame (`loadStep`) per a poder mostrar una barra de
    // progrés des de l'escena `BootLoader`.
    class Cache {
       public:
        static void init();
        static void destroy();
        static auto get() -> Cache*;

        ~Cache() = default;
        Cache(const Cache&) = delete;
        auto operator=(const Cache&) -> Cache& = delete;

        // Getters: throw runtime_error si el nom no existeix al cache.
        auto getMusic(const std::string& name) -> Ja::Music*;
        auto getSound(const std::string& name) -> Ja::Sound*;
        auto getSurfacePixels(const std::string& name) -> const std::vector<Uint8>&;
        auto getPaletteBytes(const std::string& name) -> const std::vector<Uint8>&;
        auto getTextFile(const std::string& name) -> const std::vector<uint8_t>&;

        // Loader incremental.
        void beginLoad();
        auto loadStep(int budget_ms) -> bool;  // true → DONE
        [[nodiscard]] auto isLoadDone() const -> bool { return stage_ == LoadStage::DONE; }
        [[nodiscard]] auto getProgress() const -> float;  // 0.0..1.0
        [[nodiscard]] auto getCurrentLoadingName() const -> const std::string& { return current_loading_name_; }

       private:
        Cache() = default;

        enum class LoadStage : std::uint8_t {
            MUSICS,
            SOUNDS,
            BITMAPS,
            TEXT_FILES,
            DONE,
        };

        void calculateTotal();
        void loadOneMusic(size_t index);
        void loadOneSound(size_t index);
        void loadOneBitmap(size_t index);
        void loadOneTextFile(size_t index);
        void stepEachInList(List::Type type, const std::function<void()>& clear_fn, LoadStage next, const std::function<void(size_t)>& load_fn);
        void stepTextFiles();

        std::vector<MusicResource> musics_;
        std::vector<SoundResource> sounds_;
        std::vector<SurfaceResource> surfaces_;
        std::vector<TextFileResource> text_files_;

        LoadStage stage_{LoadStage::DONE};
        size_t stage_index_{0};
        int total_count_{0};
        int loaded_count_{0};
        std::string current_loading_name_;

        static std::unique_ptr<Cache> instance;
    };

}  // namespace Resource
