#pragma once

#include <GameKitGrid.h>
#include <cstdint>

namespace PocketDungeon {
static constexpr uint8_t DUNGEON_COLS = 9;
static constexpr uint8_t DUNGEON_ROWS = 7;
static constexpr uint8_t TUTORIAL_ROWS = 2;
static constexpr uint8_t MAX_ENTITIES = 8;

enum class Tile : uint8_t { Floor, Wall, Stairs, Treasure };
enum class EntityType : uint8_t { Player, Slime, Bat };
enum class MoveResult : uint8_t { None, Moved, Blocked, Attacked, Treasure, Stairs, Dead };

struct Entity {
    EntityType type = EntityType::Slime;
    GameKit::GridPos pos {};
    int8_t hp = 1;
    bool alive = false;
};

struct DungeonState {
    Tile tiles[DUNGEON_ROWS][DUNGEON_COLS] {};
    Entity entities[MAX_ENTITIES] {};
    uint8_t entityCount = 0;
    GameKit::GridPos playerPos {1, 1};
    uint16_t floor = 0; // 0,1 tutorial, 2+ real
    uint16_t gold = 0;
    int8_t hp = 5;
    bool gameOver = false;
    uint8_t renderRows = DUNGEON_ROWS;
};

class DungeonModel {
    DungeonState state {};
    uint32_t seed = 0xC0FFEE;
    uint16_t bestFloor = 1;
    uint16_t bestGold = 0;

    uint32_t nextRandom();
    void addEnemy(EntityType type, GameKit::GridPos pos, int8_t hp);
    int findEnemyAt(GameKit::GridPos pos) const;
    bool isWalkable(GameKit::GridPos pos) const;
    void moveMonsters();
    void generateTutorialFloor(uint8_t tId);
    void clearAllTiles();

public:
    void reset(uint32_t seedValue = 0xC0FFEE, bool tutorials = true);
    void generateFloor();
    MoveResult movePlayer(int dx, int dy);

    const DungeonState& getState() const { return state; }
    uint16_t getBestFloor() const { return bestFloor; }
    uint16_t getBestGold() const { return bestGold; }
    void setBests(uint16_t floor, uint16_t gold) { bestFloor = floor; bestGold = gold; }
    bool isTutorial() const { return state.floor < 2; }
    uint8_t tutorialId() const { return static_cast<uint8_t>(state.floor); }
    uint16_t displayFloor() const { return state.floor < 2 ? 1 : state.floor - 1; }
};

} // namespace PocketDungeon
