#pragma once

#include <cstdint>        // Para uint8_t
#include <string>         // Para string
#include <unordered_map>  // Para unordered_map
#include <utility>        // Para move
#include <vector>         // Para vector

// --- Clase Asset: gestor optimizado de recursos (singleton) ---
class Asset {
   public:
    // --- Enums ---
    enum class Type : int {
        BITMAP,     // Imágenes
        MUSIC,      // Música
        SOUND,      // Sonidos
        FONT,       // Fuentes
        LANG,       // Idiomas
        DATA,       // Datos
        DEMODATA,   // Datos de demo
        ANIMATION,  // Animaciones
        PALETTE,    // Paletas
        SIZE,       // Tamaño
    };

    // --- Métodos de singleton ---
    static void init(const std::string& executable_path);
    static void destroy();
    static auto get() -> Asset*;
    Asset(const Asset&) = delete;
    auto operator=(const Asset&) -> Asset& = delete;

    // --- Métodos para la gestión de recursos ---
    void add(const std::string& file_path, Type type, bool required = true, bool absolute = false);
    void loadFromFile(const std::string& config_file_path, const std::string& prefix = "", const std::string& system_folder = "");  // Con soporte para variables
    [[nodiscard]] auto getPath(const std::string& filename) const -> std::string;
    [[nodiscard]] auto loadData(const std::string& filename) const -> std::vector<uint8_t>;  // Carga datos del archivo
    [[nodiscard]] auto check() const -> bool;
    [[nodiscard]] auto getListByType(Type type) const -> std::vector<std::string>;
    [[nodiscard]] auto exists(const std::string& filename) const -> bool;  // Nueva función para verificar existencia

   private:
    // --- Estructuras privadas ---
    struct Item {
        std::string file;  // Ruta completa del archivo
        Type type;         // Tipo de recurso
        bool required;     // Indica si el archivo es obligatorio

        Item(std::string path, Type asset_type, bool is_required)
            : file(std::move(path)),
              type(asset_type),
              required(is_required) {}
    };

    // --- Variables internas ---
    std::unordered_map<std::string, Item> file_list_;  // Mapa para búsqueda O(1)
    std::string executable_path_;                      // Ruta del ejecutable

    // --- Métodos internos ---
    [[nodiscard]] auto checkFile(const std::string& path) const -> bool;                                                                              // Verifica si un archivo existe
    [[nodiscard]] static auto getTypeName(Type type) -> std::string;                                                                                  // Obtiene el nombre del tipo
    [[nodiscard]] static auto parseAssetType(const std::string& type_str) -> Type;                                                                    // Convierte string a tipo
    void addToMap(const std::string& file_path, Type type, bool required, bool absolute);                                                             // Añade archivo al mapa
    [[nodiscard]] static auto replaceVariables(const std::string& path, const std::string& prefix, const std::string& system_folder) -> std::string;  // Reemplaza variables en la ruta
    static auto parseOptions(const std::string& options, bool& required, bool& absolute) -> void;                                                     // Parsea opciones

    // --- Constructores y destructor privados (singleton) ---
    explicit Asset(std::string executable_path)  // Constructor privado
        : executable_path_(std::move(executable_path)) {}
    ~Asset() = default;  // Destructor privado

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