#pragma once

#include <optional>
#include <string>
#include <vector>

#include <QPoint>
#include <QWidget>

#include "BeltSystem.h"
#include "Building.h"
#include "BuildingId.h"
#include "EntitySelectionChangedEvent.h"
#include "EventHandler.h"
#include "GameConfig.h"
#include "PlayerCommandsAppliedEvent.h"
#include "RecipesConfig.h"
#include "DebrisSelectionChangedEvent.h"
#include "SelectionChangedEvent.h"
#include "ShipLayout.h"
#include "ShipsConfig.h"
#include "Tick.h"
#include "TickAdvancedEvent.h"

class Simulation;
class FieldSelectionPanel;
class ShipLayoutPreview;
class QLabel;
class QListWidget;
class QPushButton;
class QVBoxLayout;

// Shows the current selection. The building category (buildings and construction sites)
// is rendered by this panel itself; the field category (ships, defence stations, debris)
// is rendered by the embedded FieldSelectionPanel.
//
// The two categories are mutually exclusive (REQ-UI-SELECTION-CATEGORIES) and this panel
// is the sole arbiter of which one owns the content: it listens to all three selection
// events, forwards the field ones to the child panel, and drops the losing category's
// content. Neither panel touches the other's widgets.
class SelectedBuildingPanel : public QWidget,
                               public CombinedEventHandler<TickAdvancedEvent,
                                                           PlayerCommandsAppliedEvent,
                                                           EntitySelectionChangedEvent,
                                                           SelectionChangedEvent,
                                                           DebrisSelectionChangedEvent>
{
    Q_OBJECT

public:
    SelectedBuildingPanel(Simulation* sim, const GameConfig* config,
                          QWidget* parent = nullptr);
    ~SelectedBuildingPanel() override;

private:
    void handleEvent(std::shared_ptr<const TickAdvancedEvent> event) override;
    void handleEvent(std::shared_ptr<const PlayerCommandsAppliedEvent> event) override;
    void handleEvent(std::shared_ptr<const EntitySelectionChangedEvent> event) override;
    void handleEvent(std::shared_ptr<const SelectionChangedEvent> event) override;
    void handleEvent(std::shared_ptr<const DebrisSelectionChangedEvent> event) override;

private slots:
    void onSelectRecipeClicked();
    void onClearBelt();
    void onSplitterFilterChanged();

private:
    // Why the selection display is being refreshed. A periodic tick only needs a
    // lightweight content update (e.g. a construction site's progress label),
    // whereas an applied player command may have changed the configuration and
    // needs a full structural rebuild.
    enum class RefreshReason
    {
        PeriodicTick,
        CommandApplied
    };

    void onSelectionChanged(const std::vector<BuildingId>& ids);
    // Gives the panel to the field category once it has anything selected.
    void yieldToFieldSelection();
    void refreshSelectionDisplay(RefreshReason reason);
    void rebuild();
    void hideAllWidgets();
    void buildEmpty();
    void buildSingle(BuildingId id);
    void buildMulti(const std::vector<BuildingId>& ids);
    void refreshBuffers(const Building* b);
    void refreshSiteProgress(const ConstructionSite* s);
    void updateShipyardLayoutWidgets(BuildingType type,
                                     const std::string& recipeId,
                                     const std::optional<ShipLayoutConfig>& shipLayout);
    void buildSplitterFilters(const std::optional<BeltSystem::SplitterInfo>& info);
    const RecipeDef* findRecipe(const Building* b) const;
    const ShipDef*   findShipDef(const std::string& id) const;
    std::vector<std::string> getAllItemIds() const;

    Simulation*        m_sim;
    const GameConfig*  m_config;
    std::vector<BuildingId> m_selectedBuildingIds;

    QVBoxLayout* m_layout;
    QLabel*      m_titleLabel;
    QPushButton* m_recipeSelectButton;
    QPushButton* m_clearBeltBtn;
    QLabel*      m_filterALabel;
    QListWidget* m_filterAList;
    QLabel*      m_filterBLabel;
    QListWidget* m_filterBList;
    QLabel*      m_buffersLabel;

    ShipLayoutPreview* m_layoutPreview;
    QPushButton*       m_configureLayoutBtn;

    std::optional<BuildingId> m_singleBuildingId;
    bool         m_singleIsSite = false;  // selected single entity is a construction site
    QPoint       m_splitterTile;
    std::string  m_currentRecipeId;

    // Renders the field selection (actors + debris) below the building content
    // (REQ-UI-FIELD-MULTI-SELECTION). Hides itself while nothing field-side is selected.
    FieldSelectionPanel* m_fieldSelectionPanel;
};
