#ifndef _LIVOX_GEN1_PCLOUD_DARK_AMBIENCE_STIMULUS_BUFFER_H
#define _LIVOX_GEN1_PCLOUD_DARK_AMBIENCE_STIMULUS_BUFFER_H

#include <cstddef>
#include <cstdint>
#include <memory>
#include <optional>
#include <user/deviceAttachmentSpec.h>
#include <user/intrin.h>
#include <user/intrinThresholdParams.h>
#include <user/stagingBuffer.h>
#include <user/stimulusBuffer.h>
#include "pcloudAmbienceQualeIfaceApi.h"

namespace smo {
namespace stim_buff {

class StimulusProducer;

/**
 * Sensory pcloudDarkAmbience buffer: one uint32 stimspot per stimframe —
 * the count of per-frame slots whose average intensity falls below the
 * qualeIface's passband-count-lt-val. A DAP spec may optionally attach a
 * postrin(...) specifier (scene is "too good, stay here"); negtrin is not
 * valid on this qualeIfaceApi.
 */
class PcloudDarkAmbienceStimulusBuffer
:	public StimulusBuffer
{
public:
	explicit PcloudDarkAmbienceStimulusBuffer(
		StimulusProducer& parent,
		const std::shared_ptr<device::DeviceAttachmentSpec>& deviceAttachmentSpec,
		int histbuffMs,
		const StagingBuffer::IOEngineConstraints& inputEngineConstraints,
		const StagingBuffer::IOEngineConstraints& outputEngineConstraints,
		const SmoCallbacks& callbacks,
		cl_mem_flags flags,
		size_t nDgramsPerFrame_)
	:	StimulusBuffer(
			parent, deviceAttachmentSpec, histbuffMs,
			inputEngineConstraints, outputEngineConstraints,
			callbacks, flags),
	nDgramsPerFrame(nDgramsPerFrame_)
	{
		intrin::validateNoIntrinParamsOnQualeIface(
			deviceAttachmentSpec->qualeIfaceApi,
			deviceAttachmentSpec->qualeIfaceApiParams);

		passbandCountLtComparator =
			parsePcloudDarkAmbienceLtComparator(deviceAttachmentSpec);

		if (!deviceAttachmentSpec->negtrin.empty())
		{
			throw std::runtime_error(
				"pcloudDarkAmbience DAP spec for device '"
				+ deviceAttachmentSpec->deviceIdentifier
				+ "' declares a negtrin(...); negtrin belongs on a "
				"pcloudLightAmbience line, not pcloudDarkAmbience.");
		}

		if (!deviceAttachmentSpec->postrin.empty())
		{
			postrinInterestConfig = parseAmbienceIntrinConfigFromParams(
				"postrin",
				deviceAttachmentSpec->postrinParams,
				nDgramsPerFrame_);
		}
	}

	~PcloudDarkAmbienceStimulusBuffer() = default;

	PcloudDarkAmbienceStimulusBuffer(
		const PcloudDarkAmbienceStimulusBuffer&) = delete;
	PcloudDarkAmbienceStimulusBuffer& operator=(
		const PcloudDarkAmbienceStimulusBuffer&) = delete;
	PcloudDarkAmbienceStimulusBuffer(
		PcloudDarkAmbienceStimulusBuffer&&) = delete;
	PcloudDarkAmbienceStimulusBuffer& operator=(
		PcloudDarkAmbienceStimulusBuffer&&) = delete;

	bool shouldTriggerPostrinEvent(uint32_t ambiencePassbandCount) const
	{
		if (!postrinInterestConfig.has_value()) { return false; }
		return ambiencePassbandCount >= postrinInterestConfig->threshold;
	}

public:
	size_t nDgramsPerFrame;
	ParamComparator passbandCountLtComparator;
	std::optional<intrin::IntrinConfig> postrinInterestConfig;
};

} // namespace stim_buff
} // namespace smo

#endif // _LIVOX_GEN1_PCLOUD_DARK_AMBIENCE_STIMULUS_BUFFER_H
