#ifndef MAP_VIEW_HPP_
#define MAP_VIEW_HPP_

#include <ChunkHandle/ChunkHandle.hpp>
#include <GraphicsContext/GraphicsContext.hpp>
#include <MapTool/MapTool.hpp>
#include <RemoteMap/RemoteMap.hpp>
#include <Utilities/CircularInt.hpp>
#include <Widget/Widget.hpp>
#include <Item/IEquipment.hpp>
#include <Entity/PhysicsEntity/CameraEntity/Player/Player.hpp>
#include <cstdint>
#include <functional>
#include <unordered_map>

class WorldDisplay;

/**
 * @brief A widget displaying an interactive map of the world. 
 */
class MapView final : public Widget
{
private:
    using GenerateMaterialCallback = std::function<void()>;

    std::vector<GenerateMaterialCallback> materialQueue;
    RemoteMap &remoteMap;
    std::unordered_map<uint64_t, std::shared_ptr<Material>> tileMaterials;
    BoundingBox<cint32> visibleArea = {};
    wvec2 lastCameraMinBound = wvec2(0, 0);
    wvec2 lastCameraMaxBound = wvec2(0, 0);
    MapTool* &tool;
    bool shouldTrackPlayer = false;
    Player &player;

    static constexpr int rangeZ = 10;
    static constexpr Uint32 playerBlinkPeriod = 500;

    void drawLandMark(GraphicsContext &context, Material &icon, wvec2 pos, const std::string &tooltip = "");

public:
    wvec2 cameraPos = wvec2(0);

    MapView(
        WorldDisplay &worldDisplay,
        RemoteMap &remoteMap,
        Player &player,
        MapTool* &tool
    );

    virtual ~MapView();

    /**
     * @brief Return the position on the world's XY plane, of where the cursor is currently pointing.
     */
    glm::ivec2 getHoveredMapPos();

    /**
     * @brief Open a popup relative to the cursor.
     */
    void openPopupAtCursor(glm::ivec2 offset, Widget *popup);

    /**
     * @brief Place a pin with a label at the specified position.
     */
    void placePin(const std::string &label, glm::ivec2 pos);

    /**
     * @brief Return this map view with player tracking enabled (view follows player).
     */
    MapView* withPlayerTracking();

    virtual glm::ivec2 getMinSize() override;
    virtual void draw(GraphicsContext &context) override;
    virtual void onMouseDown(Uint8 button) override;
    virtual void onMouseUp(Uint8 button) override;
    virtual void onMouseMoved(glm::ivec2 pos) override;
};

#endif