#include <psemek/audio/track.hpp>
#include <psemek/audio/constants.hpp>
#include <psemek/audio/detail/resampler.hpp>
#include <psemek/util/to_string.hpp>
#include <psemek/util/at_scope_exit.hpp>
#include <psemek/util/exception.hpp>

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif

#include <psemek/audio/audio_file/AudioFile.h>

#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

namespace psemek::audio
{

	namespace
	{

		std::vector<float> convert_audio(std::vector<std::vector<float>> const & channels, int frequency)
		{
			if (channels.empty() || channels.size() > 2)
				throw util::exception(util::to_string("Can't convert audio with ", static_cast<int>(channels.size()), " channels"));

			std::vector<float> result(channels[0].size() * 2);
			auto out = result.begin();

			if (channels.size() == 1)
			{
				for (auto p = channels[0].begin(); p != channels[0].end(); ++p)
				{
					*out++ = *p;
					*out++ = *p;
				}
			}
			else if (channels.size() == 2)
			{
				for (auto p0 = channels[0].begin(), p1 = channels[1].begin(); p0 != channels[0].end(); ++p0, ++p1)
				{
					*out++ = *p0;
					*out++ = *p1;
				}
			}

			if (frequency != audio::frequency)
			{
				audio::resampler resampler(audio::frequency * 1.f / frequency);
				resampler.feed(result);
				result = resampler.grab_result();
			}

			return result;
		}

	}

	track_ptr load_wav(util::span<char const> data)
	{
		std::vector<std::uint8_t> data_u8(data.size());
		std::copy(data.begin(), data.end(), reinterpret_cast<char *>(data_u8.data()));

		AudioFile<float> audio_file;
		audio_file.shouldLogErrorsToConsole(false);
		audio_file.onError = [](std::string const & error) {
			throw util::exception("Failed to load WAV file: " + error);
		};
		audio_file.loadFromMemory(data_u8);

		return load_raw(convert_audio(audio_file.samples, audio_file.getSampleRate()));
	}

	track_ptr load_wav(std::vector<char> const & data)
	{
		return load_wav(util::span<char const>(data));
	}

}
