#include <psemek/audio/effect/fade_out.hpp>
#include <psemek/audio/constants.hpp>

#include <algorithm>

namespace psemek::audio
{

	namespace
	{

		struct fade_out_impl
			: stream
		{
			fade_out_impl(stream_ptr stream, duration length, duration start)
				: stream_(std::move(stream))
				, length_(length)
				, start_(start)
				, total_length_(stream_->played() + start_.samples() + length_.samples())
			{}

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

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

			std::size_t read(util::span<float> samples) override
			{
				if (current_ >= length_.samples())
					return 0;

				auto result = stream_->read(samples);

				if (result <= start_.samples())
				{
					start_ -= duration::from_samples(result);
				}
				else
				{
					for (std::size_t i = start_.samples(); i < result; i += 2)
					{
						float m = static_cast<float>(length_.samples() - std::min<std::size_t>(current_, length_.samples())) / length_.samples();

						samples[i + 0] *= m;
						samples[i + 1] *= m;

						current_ += 2;
					}
					start_ = {};
				}

				return result;
			}

		private:
			stream_ptr stream_;
			duration length_;
			duration start_;
			std::size_t current_ = 0;
			std::size_t total_length_ = 0;
		};

	}

	stream_ptr fade_out(stream_ptr stream, duration length, duration start)
	{
		return std::make_shared<fade_out_impl>(std::move(stream), length, start);
	}

}
