#include "sound/engine.h"
#include <AL/al.h>
#include <AL/alc.h>
#include <glm/gtc/type_ptr.hpp>

AudioEngine::AudioEngine(std::weak_ptr<ResourceManager> _resource)
{
	// Open the default device for now
	if ((device = alcOpenDevice(NULL)) == NULL) {
		LOG(ERROR, "Failed to open default device {}", alGetError());
		return;
	}
	context = alcCreateContext(device, NULL);
	alcMakeContextCurrent(context);
	musicPlayer = std::make_unique<AudioStream>();
	soundManager = std::make_unique<SoundManager>();
	resourceManager = _resource;
	alGetError();
}

void AudioEngine::hookEventManager(std::weak_ptr<EventManager> _events)
{
	globalEventManager = _events;
}

void AudioEngine::hookSceneManager(std::weak_ptr<EventManager> _events)
{
	sceneEventManager = _events;
	if (auto weak = sceneEventManager.lock()) {
		std::weak_ptr<AudioEngine> weakSelf = shared_from_this();
		auto play_sound = [weakSelf](const std::string& id, int priority, const std::optional<glm::vec3>& pos = std::nullopt) {
			if (auto self = weakSelf.lock()) {
				if (auto res = self->resourceManager.lock()) {
					auto buf = res->loadSoundEffect(id);
					if (buf != 0) {
						if (pos != std::nullopt)
							self->soundManager->playSound(buf, priority, pos.value());
						else
							self->soundManager->playSound(buf, priority);
					} 
				}
			}
		};

		weak->subscribe<EntityFireEvent>([weakSelf,play_sound](const EntityFireEvent& e){ 
			play_sound(e.weaponType + "/shoot", 10, e.firePosition);
		});
		weak->subscribe<EntityReloadEvent>([weakSelf,play_sound](const EntityReloadEvent& e) {
			play_sound(e.weaponType + "/reload", 9, e.position);
		});
	}
}

void AudioEngine::poll()
{
	soundManager->pollSources();
}

void AudioEngine::updateListener(const glm::vec3& pos)
{
	alListenerfv(AL_POSITION, glm::value_ptr(pos));
}

void AudioEngine::pushMusic(std::string _songName)
{
	LOG(INFO, "Loading song {}", _songName);
	musicPlayer->AddToQueue(_songName);
}

void AudioEngine::playMusic()
{
	LOG(INFO, "Playing stream", NULL);
	musicPlayer->PlayStream();
}

void AudioEngine::pauseMusic()
{
	musicPlayer->PauseStream();
}

void AudioEngine::killMusic()
{
	musicPlayer->kill();
}

AudioEngine::~AudioEngine()
{
	musicPlayer->kill();
	alcMakeContextCurrent(NULL);
	alcDestroyContext(context);
	alcCloseDevice(device);
}
