#pragma once

#include <chrono>
#include <cstdint>
#include <memory>
#include <queue>

#include <Aulib/Decoder.h>
#include <SDL_mutex.h>

#include "utils/sdl_mutex.h"

namespace devilution {

/**
 * @brief A Decoder interface implementations that simply has the samples pushed into it by the user.
 */
class PushAulibDecoder final : public ::Aulib::Decoder {
public:
	PushAulibDecoder(int numChannels, int sampleRate)
	    : numChannels_(numChannels)
	    , sampleRate_(sampleRate)
	{
	}

	void PushSamples(const std::uint8_t *data, unsigned size) noexcept;
	void PushSamples(const std::int16_t *data, unsigned size) noexcept;
	void DiscardPendingSamples() noexcept;

	bool open(SDL_RWops *rwops) override;

	[[nodiscard]] int getChannels() const override
	{
		return numChannels_;
	}

	[[nodiscard]] int getRate() const override
	{
		return sampleRate_;
	}

	bool rewind() override;
	[[nodiscard]] std::chrono::microseconds duration() const override;
	bool seekToTime(std::chrono::microseconds pos) override;

protected:
	int doDecoding(float buf[], int len, bool &callAgain) override;

private:
	struct AudioQueueItem {
		std::unique_ptr<std::int16_t[]> data;
		unsigned len;
		const std::int16_t *pos;
	};

	const int numChannels_;
	const int sampleRate_;

	// Requires holding the queue_mutex_.
	AudioQueueItem *Next();

	std::queue<AudioQueueItem> queue_;
	SdlMutex queue_mutex_;
};

} // namespace devilution
