#include <psemek/audio/effect/pause.hpp>
#include <psemek/audio/detail/smooth.hpp>

#include <atomic>
#include <algorithm>

namespace psemek::audio
{

	namespace
	{

		struct pause_control_impl
			: pause_control
		{
			pause_control_impl(stream_ptr stream,  bool paused, duration length)
				: stream_(std::move(stream))
				, paused_{paused}
				, length_(length)
				, level_(paused ? 0 : length_.samples())
			{}

			bool paused() const override
			{
				return paused_.load();
			}

			bool paused(bool value) override
			{
				return paused_.exchange(value);
			}

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

			std::size_t read(util::span<float> samples) override
			{
				bool const paused = paused_.load();

				if (paused)
				{
					auto count = stream_->read(samples.prefix(std::min(samples.size(), level_)));

					for (std::size_t i = 0; i < count; i += 2)
					{
						float gain = static_cast<float>(level_) / length_.samples();
						samples[i + 0] *= gain;
						samples[i + 1] *= gain;
						level_ -= 2;
					}

					std::fill(samples.begin() + count, samples.end(), 0.f);
					return samples.size();
				}
				else
				{
					auto count = stream_->read(samples);

					auto const max_level = static_cast<std::size_t>(length_.samples());

					for (std::size_t i = 0; i < count; i += 2)
					{
						float gain = static_cast<float>(level_) / max_level;
						samples[i + 0] *= gain;
						samples[i + 1] *= gain;

						if (level_ < max_level)
							level_ += 2;
					}

					return count;
				}
			}

			std::size_t played() const override
			{
				return stream_->played();
			}

		private:
			stream_ptr stream_;
			std::atomic<bool> paused_;
			duration length_;
			std::size_t level_;
		};

	}

	std::shared_ptr<pause_control> pause(stream_ptr stream,  bool paused, duration length)
	{
		return std::make_shared<pause_control_impl>(std::move(stream), paused, length);
	}

}
