#include "levelmanager.hpp"
#include "worldbuilder.hpp"
#include "constants.hpp"
#include "save.hpp"
#include "systems.hpp"
#include "components.hpp"

using lighting::LightRender;
using std::shared_ptr, std::make_shared;
using namespace components;

LevelManager::LevelManager() {
  components::configure($components);
  create_level();
}

LevelScaling LevelManager::scale_level() {
  return {
    30 + (5 * int($current_level)),
    20 + (5 * int($current_level))
  };
}

size_t LevelManager::create_level(shared_ptr<DinkyECS::World> prev_world) {
  auto world = make_shared<DinkyECS::World>();

  if(prev_world != nullptr) {
    prev_world->clone_into(*world);
  } else {
    save::load_configs(*world);
  }

  auto scaling = scale_level();

  auto map = make_shared<Map>(scaling.map_width, scaling.map_height);
  WorldBuilder builder(*map, $components);
  builder.generate(*world);

  size_t index = $levels.size();

  auto collider = make_shared<SpatialMap>();
  // not sure if this is still needed
  System::init_positions(*world, *collider);

  $levels.emplace_back(index, map, world,
      make_shared<LightRender>(map->width(), map->height()),
      collider);

  dbc::check(index == $levels.size() - 1, "Level index is not the same as $levels.size() - 1, off by one error");
  return index;
}

GameLevel &LevelManager::next() {
  dbc::check($current_level < $levels.size(), "attempt to get next level when at end");
  $current_level++;
  return $levels.at($current_level);
}

GameLevel &LevelManager::previous() {
  dbc::check($current_level > 0, "attempt to go to previous level when at 0");
  $current_level--;
  return $levels.at($current_level);
}

GameLevel &LevelManager::current() {
  return $levels.at($current_level);
}

GameLevel &LevelManager::get(size_t index) {
  return $levels.at(index);
}
