#include "sound.hpp"
#include "dbc.hpp"
#include <fmt/core.h>
#include "config.hpp"

namespace sound {
  static SoundManager SMGR;
  static bool initialized = false;
  static bool muted = false;

  using namespace fmt;
  using std::make_shared;
  namespace fs = std::filesystem;

  SoundPair& get_sound_pair(const std::string& name) {
    dbc::check(initialized, "You need to call sound::init() first");

    if(SMGR.sounds.contains(name)) {
      // get the sound from the sound map
      return SMGR.sounds.at(name);
    } else {
      dbc::log(fmt::format("Attempted to stop {} sound but not available.",
            name));
      return SMGR.sounds.at("blank");
    }
  }


  void init() {
    if(!initialized) {
      Config assets("assets/config.json");

      for(auto& el : assets["sounds"].items()) {
        load(el.key(), el.value());
      }
      initialized = true;
    }
  }

  void load(const std::string name, const std::string sound_path) {
    dbc::check(fs::exists(sound_path), fmt::format("sound file {} does not exist", sound_path));

    // create the buffer and keep in the buffer map
    auto buffer = make_shared<sf::SoundBuffer>(sound_path);

    // set it on the sound and keep in the sound map
    auto sound = make_shared<sf::Sound>(*buffer);
    sound->setRelativeToListener(false);
    sound->setPosition({0.0f, 0.0f, 1.0f});

    SMGR.sounds.try_emplace(name, buffer, sound);
  }

  void play(const std::string name, bool loop) {
    if(muted) return;
    auto& pair = get_sound_pair(name);
    pair.sound->setLooping(loop);
    // play it
    pair.sound->play();
  }

  void stop(const std::string name) {
    auto& pair = get_sound_pair(name);
    pair.sound->stop();
  }

  bool playing(const std::string name) {
    auto& pair = get_sound_pair(name);
    auto status = pair.sound->getStatus();
    return status == sf::SoundSource::Status::Playing;
  }

  void play_at(const std::string name, float x, float y, float z) {
    auto& pair = get_sound_pair(name);
    pair.sound->setPosition({x, y, z});
    pair.sound->play();
  }

  void mute(bool setting) {
    muted = setting;
  }
}