/* ***********************************************************************
//
//   Copyright (C) 2025 -- The 4D-STAR Collaboration
//   File Author: Emily Boudreaux
//   Last Modified: March 20, 2025
//
//   4DSSE is free software; you can use it and/or modify
//   it under the terms and restrictions the GNU General Library Public
//   License version 3 (GPLv3) as published by the Free Software Foundation.
//
//   4DSSE is distributed in the hope that it will be useful,
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//   See the GNU Library General Public License for more details.
//
//   You should have received a copy of the GNU Library General Public License
//   along with this software; if not, write to the Free Software
//   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// *********************************************************************** */
#pragma once

#include <vector>
#include <string>
#include <stdexcept>
#include <unordered_map>

#include "resourceManagerTypes.h"
#include "config.h"
#include "probe.h"
#include "quill/LogMacros.h"

/**
 * @class ResourceManager
 * @brief Manages resources within the application.
 *
 * The ResourceManager class is responsible for loading, storing, and providing access to resources.
 * It follows the Singleton design pattern to ensure only one instance of the manager exists.
 */
namespace serif::resource {
    class ResourceManager {
    private:
        /**
         * @brief Private constructor to prevent instantiation.
         */
        ResourceManager();

        /**
         * @brief Deleted copy constructor to prevent copying.
         */
        ResourceManager(const ResourceManager&) = delete;

        /**
         * @brief Deleted assignment operator to prevent assignment.
         */
        ResourceManager& operator=(const ResourceManager&) = delete;

        serif::config::Config& m_config = serif::config::Config::getInstance();
        serif::probe::LogManager& m_logManager = serif::probe::LogManager::getInstance();
        quill::Logger* m_logger = m_logManager.getLogger("log");

        serif::config::Config m_resourceConfig;
        std::string m_dataDir;
        std::unordered_map<std::string, types::Resource> m_resources;

        /**
         * @brief Loads a resource by name.
         * @param name The name of the resource to load.
         * @return True if the resource was loaded successfully, false otherwise.
         */
        bool load(const std::string& name);

    public:
        /**
         * @brief Gets the singleton instance of the ResourceManager.
         * @return The singleton instance of the ResourceManager.
         */
        static ResourceManager& getInstance() {
            static ResourceManager instance;
            return instance;
        }

        /**
         * @brief Gets a list of available resources.
         * @return A vector of strings containing the names of available resources.
         *
         * Example usage:
         * @code
         * ResourceManager& manager = ResourceManager::getInstance();
         * std::vector<std::string> resources = manager.getAvailableResources();
         * @endcode
         */
        std::vector<std::string> getAvailableResources() const;

        /**
         * @brief Gets a resource by name.
         * @param name The name of the resource to retrieve.
         * @return A constant reference to the requested resource.
         * @throws std::runtime_error if the resource is not found.
         *
         * Example usage:
         * @code
         * ResourceManager& manager = ResourceManager::getInstance();
         * const Resource& resource = manager.getResource("exampleResource");
         * @endcode
         */
        const types::Resource& getResource(const std::string &name) const;

        /**
         * @brief Loads a resource by name.
         * @param name The name of the resource to load.
         * @return True if the resource was loaded successfully, false otherwise.
         *
         * Example usage:
         * @code
         * ResourceManager& manager = ResourceManager::getInstance();
         * bool success = manager.loadResource("exampleResource");
         * @endcode
         */
        bool loadResource(std::string& name);

        /**
         * @brief Loads all resources.
         * @return An unordered map with resource names as keys and load success as values.
         *
         * Example usage:
         * @code
         * ResourceManager& manager = ResourceManager::getInstance();
         * std::unordered_map<std::string, bool> results = manager.loadAllResources();
         * @endcode
         */
        std::unordered_map<std::string, bool> loadAllResources();
    };
}
