#ifndef ROGUE_WORLD_H
#define ROGUE_WORLD_H

#include <optional>
#include <utility>
#include <vector>
#include <SDL2/SDL_rect.h>
#include "character.h"
#include "core/input.h"
#include "core/roguedefs.h"

namespace rogue {
class Character;

struct TileData {
	Character *character{nullptr};
	bool is_wall{false};
};

struct Room {
	// bitmask of hallways
	Directions hallway_paths{0};
	int chunk_size{0};
	bool initialized{false};
	// the starting tile and length of the walls
	SDL_Rect rect{0, 0, 1, 1};
	void draw(Tile pivot);
	bool tile_is_wall(Tile local_tile) const;
};

struct World {
	friend class WorldGenerator;
	World();
	~World() = default;
	void act_if_requested();
	void act();
	void render();
	Room &get_room(Chunk chunk);
	Character *get_player();
	Character *get_boss();
	Chunk get_chunk(Tile tile);
	TileData query_tile(Tile tile);
	void on_input(bool);
private:
	int chunk_size{1};
	unsigned shear{0};
	bool turn_requested{false};
	Character player{};
	Character boss{};
	std::vector<Room> rooms{};
	std::vector<Character> characters{};
	KeyEventHandler direction_pressed;
};

class WorldGenerator {
public:
	WorldGenerator() = default;
	WorldGenerator &with_chunk_size(unsigned side_length);
	WorldGenerator &with_world_size(unsigned side_length);
	WorldGenerator &with_room_size(unsigned min_side_length, unsigned max_side_length);
	WorldGenerator &with_player(std::function<Character(Tile)> spawner);
	WorldGenerator &with_enemy(std::function<Character(Tile)> spawner, int inv_frequency);
	WorldGenerator &with_boss(std::function<Character(Tile)> spawner);
	WorldGenerator &with_connecting_chance(unsigned num);
	std::unique_ptr<World> generate();
private:
	void generate_world(std::unique_ptr<World> &world, Chunk start);
	void generate_room(std::unique_ptr<World> &world, Chunk const &last);
	void add_enemies(std::unique_ptr<World> &world, Chunk const &chunk, Room &room);
	void setup_player(std::unique_ptr<World> &world, Chunk spawn_chunk);
private:
	std::function<Character(Tile)> player_spawner{};
	std::function<Character(Tile)> boss_spawner{};
	std::vector<std::pair<std::function<Character(Tile)>, int>> enemy_spawners{};
	int chunk_side_length{0}, world_side_length{0};
	int max_room_size{0}, min_room_size{0};
	unsigned connecting_chance{1};
	bool boss_generated{false};
};
}

#endif // !ROGUE_WORLD_H
