#include <psemek/audio/combine/duplicate.hpp>

#include <atomic>

namespace psemek::audio
{

	namespace
	{

		struct duplicate_stream_impl
			: stream
		{
			duplicate_stream_impl(std::shared_ptr<recorder> recorder)
				: recorder_(std::move(recorder))
			{}

			std::optional<std::size_t> length() const override
			{
				return recorder_->channel()->stream()->length();
			}

			std::size_t played() const override
			{
				return played_.load();
			}

			std::size_t read(util::span<float> samples) override
			{
				auto buffer = recorder_->buffer();
				auto played = played_.load();
				if (buffer.size() < played + samples.size())
				{
					recorder_->request(samples.size());
					buffer = recorder_->buffer();
				}

				auto count = std::min<std::size_t>(samples.size(), buffer.size() - played);
				std::copy(buffer.data() + played, buffer.data() + played + count, samples.begin());
				played_.fetch_add(count);
				return count;
			}

		private:
			std::shared_ptr<recorder> recorder_;
			std::atomic<std::size_t> played_{0};
		};

		struct duplicate_track_impl
			: track
		{
			duplicate_track_impl(std::shared_ptr<recorder> recorder)
				: recorder_(std::move(recorder))
			{}

			stream_ptr stream() const override
			{
				return std::make_shared<duplicate_stream_impl>(recorder_);
			}

			std::optional<std::size_t> length() const override
			{
				return recorder_->channel()->stream()->length();
			}

		private:
			std::shared_ptr<recorder> recorder_;
		};

	}

	track_ptr make_duplicator(std::shared_ptr<recorder> recorder)
	{
		return std::make_shared<duplicate_track_impl>(std::move(recorder));
	}

	track_ptr make_duplicator(stream_ptr stream)
	{
		return make_duplicator(make_recorder(std::move(stream)));
	}

	std::pair<stream_ptr, stream_ptr> duplicate(stream_ptr stream)
	{
		auto track = make_duplicator(std::move(stream));
		return {track->stream(), track->stream()};
	}

}
