#pragma once

#include <string>  // para string, basic_string
#include <utility>
#include <vector>  // para vector

#include "utils/utils.hpp"

enum class AssetType : int {
    DATA,
    BITMAP,
    ANIMATION,
    MUSIC,
    SOUND,
    FONT,
    ROOM,
    TILEMAP,
    PALETTE,
    MAX_ASSET_TYPE
};

// Clase Asset
class Asset {
    private:
        // [SINGLETON] Objeto asset privado para Don Melitón
        static Asset* asset;

        // Estructura para definir un item
        struct AssetItem {
                std::string file;  // Ruta del fichero desde la raíz del directorio
                AssetType type;    // Indica el tipo de recurso
                bool required;     // Indica si es un fichero que debe de existir

                // Constructor
                AssetItem(std::string file_path, AssetType asset_type, bool is_required)
                    : file(std::move(file_path)),
                      type(asset_type),
                      required(is_required) {}
        };

        // Variables
        int longest_name_ = 0;              // Contiene la longitud del nombre de fichero mas largo
        std::vector<AssetItem> file_list_;  // Listado con todas las rutas a los ficheros
        std::string executable_path_;       // Ruta al ejecutable

        // Comprueba que existe un fichero
        static auto checkFile(const std::string& path) -> bool;

        // Devuelve el nombre del tipo de recurso
        static auto getTypeName(AssetType type) -> std::string;

        // Constructor
        explicit Asset(const std::string& executable_path)
            : executable_path_(getPath(executable_path)) {}

        // Destructor
        ~Asset() = default;

    public:
        // [SINGLETON] Crearemos el objeto con esta función estática
        static void init(const std::string& executable_path);

        // [SINGLETON] Destruiremos el objeto con esta función estática
        static void destroy();

        // [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
        static auto get() -> Asset*;

        // Añade un elemento a la lista
        void add(const std::string& file, AssetType type, bool required = true, bool absolute = false);

        // Devuelve la ruta completa a un fichero a partir de una cadena
        [[nodiscard]] auto get(const std::string& text) const -> std::string;

        // Comprueba que existen todos los elementos
        [[nodiscard]] auto check() const -> bool;

        // Devuelve la lista de recursos de un tipo
        [[nodiscard]] auto getListByType(AssetType type) const -> std::vector<std::string>;
};