#pragma once

#include <vector>

#include <QRect>
#include <QString>
#include <QWidget>

#include "ControlAction.h"
#include "FloatingPanel.h"

class GameWorldView;
class QLabel;
class QScrollArea;
class QTimer;
class QVBoxLayout;

// Shows the controls available in the player's current situation
// (REQ-UI-CONTROLS-PANEL). The panel decides nothing: which rows apply is
// ControlAction.h's answer, the same one the key handling and the world view's mouse
// dispatch act on, so what is shown and what happens cannot part company
// (REQ-UI-CONTROLS-ACCURACY).
//
// It floats over the game world at the left edge, bottom-aligned within the band its
// owner hands it, and collapses to its heading when the heading is clicked.
//
// Refreshed on a timer rather than by subscribing to events: two of the things that
// change a row -- a belt drag starting, the ghost moving over a transfer target --
// happen on mouse movement and publish nothing, and they still have to be reflected
// while the game is paused, so there is no tick to hang it on either. The rebuild is
// skipped unless the resolved content actually differs, which is a vector of enums to
// compare.
class ControlsPanel : public QWidget, public FloatingPanel
{
    Q_OBJECT

public:
    // Neither pointer is owned; both must outlive this widget. The view is the source
    // of the control context, being the widget that owns the build mode and the
    // selection.
    ControlsPanel(const GameWorldView* view, QWidget* parent = nullptr);

    // Places the panel in the bottom-left corner of the game world view. It shares the
    // bottom edge with the build button bar rather than clearing its strip, the bar
    // being centered and sized to its buttons and so usually leaving the left free; it
    // rises above the bar only when the two would otherwise overlap
    // (REQ-UI-CONTROLS-PANEL, REQ-UI-BUILD-BAR). The bar is the only thing placed before
    // it, so it is the only rect it ever has to rise above.
    void placeIn(const QRect& viewRect,
                 const std::vector<QRect>& occupiedRects) override;

protected:
    // Clicking the heading collapses and expands the panel (REQ-UI-CONTROLS-PANEL).
    void mousePressEvent(QMouseEvent* event) override;

private:
    // Re-resolves the context and rebuilds only if the rows or the heading changed.
    void refresh();
    // Replaces the rows with those of the current context.
    void rebuild(const ControlContext& context);
    // The heading's "<name> * <detail>" text for the context, detail omitted when the
    // context has none.
    QString getHeadingText(const ControlContext& context) const;
    // Asks for the placement pass to be re-run, the panel's own size having changed.
    void invalidateLayout();

    const GameWorldView* m_view;

    QLabel*      m_heading;
    // Scrolls the rows once they outgrow the space the panel has (REQ-UI-CONTROLS-PANEL).
    // The heading is deliberately outside it, so it stays put and stays clickable.
    QScrollArea* m_scrollArea;
    QWidget*     m_rows;
    QVBoxLayout* m_rowsLayout;
    QTimer*      m_refreshTimer;

    // What is currently drawn, so a refresh that resolves to the same thing does
    // nothing. The always-available block is kept separately because the divider
    // between the two is part of what is drawn.
    QString                    m_shownHeading;
    std::vector<ControlAction> m_shownContextActions;
    std::vector<ControlAction> m_shownAlwaysActions;

    // Survives context changes and simulation restarts; presentation only, never a
    // command (REQ-UI-CONTROLS-PANEL).
    bool m_collapsed = false;
};
