#include "gui/fsm.hpp"
#include "graphics/textures.hpp"
#include "game/sound.hpp"
#include "ai/ai.hpp"
#include <iostream>
#include "graphics/shaders.hpp"
#include "gui/backend.hpp"
#include "game/level.hpp"
#include "graphics/camera.hpp"
#include "game/systems.hpp"


void play_game(std::shared_ptr<gui::FSM> main) {
  sound::play("ambient_1", true);
  main->event(game::Event::START);

  while(main->active()) {
    main->update();
    main->render();

    // BUG: need to sort out how to deal with this in the FSM
    if(main->in_state(gui::State::IDLE)
        || main->in_state(gui::State::START_SCENE)
        || main->in_state(gui::State::INTRO)
        || main->in_state(gui::State::WIN_SCENE)
        || main->in_state(gui::State::DEATH_SCENE)
        || main->in_state(gui::State::NEXT_LEVEL_SCENE)
        || main->in_state(gui::State::LOOTING))
    {
      main->handle_keyboard_mouse();
    } else{
      main->event(game::Event::TICK);
    }

    main->handle_world_events();
  }
}

int main(int argc, char* argv[]) {
  try {
    gui::Backend backend;

    shaders::init();
    components::init();
    guecs::init(&backend);
    ai::init("ai");
    GameDB::init();
    cinematic::init();
    sound::mute(true);

    sf::RenderWindow window(sf::VideoMode({SCREEN_WIDTH, SCREEN_HEIGHT}), "Zed's Raycaster Thing");
    window.setVerticalSyncEnabled(VSYNC);
    if(FRAME_LIMIT) window.setFramerateLimit(FRAME_LIMIT);
    window.setPosition({0,0});

    auto main = std::make_shared<gui::FSM>(window);

    while(true) {
      play_game(main);

      if(main->in_state(gui::State::END_QUIT)) {
        return 0;
      } else if(main->in_state(gui::State::END_PLAYER_DIED)) {
        System::restart();
        main = std::make_shared<gui::FSM>(window);
      } else if(main->in_state(gui::State::END_PLAY_AGAIN)) {
        System::restart();
        main = std::make_shared<gui::FSM>(window);
      } else {
        dbc::sentinel("Unknown game end state");
      }
    }
  } catch(const std::system_error& e) {
    std::cout << "WARNING: On OSX you'll get this error on shutdown.\n";
    std::cout << "Caught system_error with code "
                 "[" << e.code() << "] meaning "
                 "[" << e.what() << "]\n";
  }
}
