#pragma once
#include "algos/matrix.hpp"
#include "game/map.hpp"
#include "algos/pathing.hpp"
#include <functional>

namespace maze {

  struct Builder {
    size_t $width = 0;
    size_t $height = 0;
    Matrix& $walls;
    std::vector<Room>& $rooms;
    std::unordered_map<Point, bool>& $doors;
    std::vector<Point>& $dead_ends;
    std::unordered_map<Point, bool> $ends_map;
    Room $no_rooms_region{0,0,0,0};
    // BUG: instead of bool map it to the room?
    Pathing $pathing;

    Builder(Map& map) :
      $width(map.$width), $height(map.$height), $walls(map.$walls),
      $rooms(map.$rooms), $doors(map.$doors), $dead_ends(map.$dead_ends), $pathing{$width, $height}
    {
      dbc::check($width % 2 == 1, "map width not an ODD number (perimter dead ends bug)");
      dbc::check($height % 2 == 1, "map height not an ODD number (perimter dead ends bug)");

      clear();
    }

    void clear();
    void hunt_and_kill(Point on={1,1});
    void place_rooms();
    void enclose();
    void randomize_rooms(size_t room_size);
    void inner_donut(float outer_rad, float inner_rad);
    void inner_box(size_t outer_size, size_t inner_size);
    void divide(Point start, Point end);
    void remove_dead_ends();
    void dump(const std::string& msg, bool path_too=false);
    void open_box(size_t outer_size);
    void add_dead_end(Point at);
    bool room_should_exist(Room& room, bool allow_dupes=false);
    void place_doors();
    bool validate();
    bool repair();
    void punch_dead_end(size_t at_x, size_t at_y, size_t x, size_t y);
    bool space_available(size_t x, size_t y);
    int compute_paths(size_t x, size_t y);
    bool valid_door(size_t x, size_t y);
  };

  std::pair<Builder, bool> script(Map& map, nlohmann::json& config);
}
