#ifndef SCRIPTED_WORLD_HPP_
#define SCRIPTED_WORLD_HPP_

#include <ScriptEngine/ScriptEngine.hpp>
#include <World/LocalWorld/LocalWorld.hpp>
#include <string>
#include <unordered_map>

/**
 * @brief A world which executes a world script.
 */
class ScriptedWorld final : public LocalWorld
{
private:
    class Agent final
    {
    private:
        ScriptedWorld &world;
        glm::ivec3 pos;
        Side sideFacing;
        ScriptEngine engine;
        bool ok = true;
    
    public:
        Agent(
            ScriptedWorld &world,
            std::string scriptPath,
            glm::ivec3 pos,
            Side sideFacing,
            const std::unordered_map<std::string, std::string> &params
        );

        bool isOK() const;

        /**
         * @brief Updates the agent, returns true if the agent should stay running.
         */
        bool update();
    };

    std::string scriptDir;
    std::list<std::unique_ptr<Agent>> agents;

    void spawnAgent(std::string type, glm::ivec3 pos, Side sideFacing, const std::unordered_map<std::string, std::string> &params);

public:
    /**
     * @brief Construct a scripted world.
     * 
     * @param worldDir The world directory.
     * @param scriptDir The directory with this world script.
     * @param initialAgentType The type of the initial agent.
     * @param agentStartPos The starting position of the initial agent.
     */
    ScriptedWorld(std::string worldDir, std::string scriptDir, std::string initialAgentType, glm::ivec3 agentStartPos);

    /**
     * @brief Returns true if there are no more agents running.
     */
    bool isDone();

    virtual void sendMessageToEntity(uint64_t id, const void *msg, size_t size) override;
    virtual void sendCreateEntityMessageToClients(std::shared_ptr<Entity> entity) override;
    virtual void sendDeleteEntityMessageToClients(uint64_t id) override;
    virtual void onPlayerUpdateOver(Player &player) override;
    virtual void drawBlockSelector(GraphicsContext &context, WorldDisplay &worldDisplay, Player &player) override;
    virtual void onPlayerMessage(Player &player, const void *msg, size_t size) override;
    virtual void playSound(Sound &sound, glm::ivec3 blockPos, glm::vec3 vel) override;
    virtual void fastUpdate(ChunkWindow *chunkWindow) override;
    virtual void update() override;
    virtual std::shared_ptr<Player> getPlayer(const std::string &userName) override;
};

#endif