#pragma once

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

#include <QDialog>
#include <QPoint>

#include "GameConfig.h"
#include "Rotation.h"
#include "ShipLayout.h"
#include "ShipLayoutBlueprint.h"

class ItemIconCache;
class QPushButton;
class RecipeLineRow;
class SectionBox;
class ShipStatsPanel;

class ShipLayoutDialog : public QDialog
{
    Q_OBJECT

public:
    // itemIcons draws what each module costs and what the layout costs in total
    // (REQ-MOD-UI-DIALOG, REQ-MOD-UI-STATS-PANEL). Not owned.
    ShipLayoutDialog(const GameConfig* config,
                     const std::string& shipId,
                     const ShipLayoutConfig& currentLayout,
                     std::vector<ShipLayoutBlueprint>& allBlueprints,
                     std::set<std::string> unlockedModuleIds,
                     bool debugDraw,
                     ItemIconCache* itemIcons,
                     QWidget* parent = nullptr);

    std::optional<ShipLayoutConfig> getResult() const;

protected:
    void keyPressEvent(QKeyEvent* event) override;

signals:
    void gridCellClicked(QPoint cell);

private slots:
    void onModuleButtonClicked(int index);
    void onConfirm();
    void onCancel();

public:
    struct CellInfo
    {
        bool buildable;
        std::optional<int> moduleIndex;  // nullopt if empty
    };

private:

    void rebuildOccupancy();
    void updateGridWidget();
    void updateStats();
    bool canPlaceModule(const ModuleDef& def, QPoint position, Rotation rotation) const;
    std::vector<std::string> rotatedMask(const ModuleDef& def, Rotation rotation) const;
    void loadLayoutBlueprint(const std::vector<PlacedModule>& modules);

    const GameConfig* m_config;
    ItemIconCache* m_itemIcons;
    std::string m_shipId;
    std::set<std::string> m_unlockedModuleIds;
    std::vector<std::string> m_shipLayout;
    int m_rows;
    int m_cols;

    std::vector<PlacedModule> m_placedModules;
    std::vector<std::vector<CellInfo>> m_grid;

    // The module to place, as an index into config modules; nullopt when no
    // module is selected for placement. m_removeMode is a separate mode in which
    // clicking a cell removes the module there (mutually exclusive with a
    // selected module).
    std::optional<int> m_activeModuleIndex;
    bool m_removeMode = false;
    Rotation m_currentRotation;

    std::vector<QPushButton*> m_moduleButtons;
    QPushButton* m_removeButton;
    QWidget* m_gridWidget;
    ShipStatsPanel* m_statsPanel;
    SectionBox* m_buildCostSection;
    RecipeLineRow* m_buildCostLine;
    bool m_debugDraw;

    std::optional<ShipLayoutConfig> m_result;
};
