#pragma once

#include <map>
#include <memory>
#include <optional>
#include <string>
#include <vector>

#include <QRect>
#include <QWidget>

#include "BuilderModeExitedEvent.h"
#include "BuildHotkeyPressedEvent.h"
#include "BuildingBlocksChangedEvent.h"
#include "BuildingType.h"
#include "DeconstructModeChangedEvent.h"
#include "EventHandler.h"
#include "FloatingPanel.h"
#include "GameConfig.h"
#include "UnlockedBuildingsChangedEvent.h"

class QPushButton;
class Simulation;
class BuildingIconCache;
class ItemIconCache;

// The build menu: one horizontal row of build buttons floating over the game world
// view (REQ-UI-BUILD-BAR). The bar is sized to its buttons and centers itself along the
// bottom edge of the rect its owner places it in. It is placed first of the floating
// widgets and so takes the space it wants outright: nothing ever moves it aside, and the
// widgets placed after it keep out of its way instead.
class BuildButtonBar : public QWidget,
                       public FloatingPanel,
                       public CombinedEventHandler<BuilderModeExitedEvent,
                                                   DeconstructModeChangedEvent,
                                                   BuildHotkeyPressedEvent,
                                                   BuildingBlocksChangedEvent,
                                                   UnlockedBuildingsChangedEvent>
{
    Q_OBJECT

public:
    // buildingIcons supplies each button's chip icon (REQ-UI-BUILD-ICON) and itemIcons
    // the building_block icon shown in each button's cost (REQ-UI-BUILD-COST). Both are
    // window-wide caches; neither is owned, and both must outlive this widget.
    BuildButtonBar(Simulation* sim, const GameConfig* config,
                   BuildingIconCache* buildingIcons, ItemIconCache* itemIcons,
                   QWidget* parent = nullptr);
    ~BuildButtonBar() override;

    // Centers the bar along the bottom edge of the game world view's rect, given in the
    // bar's parent coordinates (REQ-UI-BUILD-BAR). Nothing is occupied yet when the bar
    // is placed, so it ignores what it is handed there.
    void placeIn(const QRect& viewRect,
                 const std::vector<QRect>& occupiedRects) override;

    void clearActiveButton();

private:
    // Re-evaluates which build buttons are enabled from the current building block
    // stock (read from the simulation). If the currently selected tool can no longer
    // be afforded, it exits builder mode so the button does not stay selected.
    void updateAffordability();

    // Re-evaluates which build buttons are visible from the current per-building
    // unlock state (REQ-LOCK-BUILDING); a locked building type's button is hidden.
    void updateVisibility();

    void handleEvent(std::shared_ptr<const BuilderModeExitedEvent> event) override;
    void handleEvent(std::shared_ptr<const DeconstructModeChangedEvent> event) override;
    void handleEvent(std::shared_ptr<const BuildHotkeyPressedEvent> event) override;
    void handleEvent(std::shared_ptr<const BuildingBlocksChangedEvent> event) override;
    void handleEvent(std::shared_ptr<const UnlockedBuildingsChangedEvent> event) override;

private slots:
    void onBuildButton(int index);

private:
    Simulation*                      m_sim;
    const GameConfig*                m_config;
    BuildingIconCache*               m_buildingIcons;  // Not owned; lives in MainWindow.
    ItemIconCache*                   m_itemIcons;      // Not owned; lives in MainWindow.
    std::vector<BuildingType>        m_types;
    std::vector<QPushButton*>        m_buttons;
    std::map<BuildingType, int>      m_costs;
    std::optional<std::size_t>       m_activeIndex;
    QPushButton*                     m_deconstructButton;
};
