#include "../../include/dv-processing/noise/k_noise_filter.hpp"

#include "../../include/dv-processing/core/event.hpp"
#include "../../include/dv-processing/data/generate.hpp"

#include "boost/ut.hpp"

using namespace boost::ut;

int main() {
	"single_event"_test = [] {
		const cv::Size resolution(100, 100);

		dv::noise::KNoiseFilter filter(resolution);
		dv::EventStore store;
		store.emplace_back(100'000, resolution.width / 2, resolution.height / 2, true);

		filter.accept(store);
		expect(eq(filter.generateEvents().size(), 0ULL));
	};

	"temporal_window_not_satisfied"_test = [] {
		const cv::Size resolution(100, 100);
		const int64_t initialTimestamp = 100'000;

		dv::noise::KNoiseFilter filter(resolution);
		const int64_t timeDelta = filter.getTemporalWindowDuration().count() + 1;

		dv::EventStore store;
		for (size_t i = 0; i < 100; ++i) {
			store.emplace_back(
				initialTimestamp + (timeDelta * i), (resolution.width / 2), (resolution.height / 2), true);
		}

		filter.accept(store);
		const dv::EventStore filteredEvents = filter.generateEvents();
		expect(eq(filteredEvents.size(), 0ULL));
	};

	"spatial_window_not_satisfied"_test = [] {
		const cv::Size resolution(100, 100);
		const int64_t initialTimestamp = 100'000;

		dv::noise::KNoiseFilter filter(resolution);

		dv::EventStore store;
		for (size_t i = 1; i < 10; ++i) {
			store.emplace_back(initialTimestamp, (resolution.width / 2) + (2 * i), (resolution.height / 2), true);
		}

		filter.accept(store);
		const dv::EventStore filteredEvents = filter.generateEvents();
		expect(eq(filteredEvents.size(), 0ULL));
	};

	"all_conditions_satisfied"_test = [] {
		const cv::Size resolution(100, 100);
		const int64_t initialTimestamp = 100'000;

		dv::noise::KNoiseFilter filter(resolution);
		const int64_t timeDelta = filter.getTemporalWindowDuration().count() - 1;

		dv::EventStore store;
		size_t numTimeBins = 100;
		for (size_t i = 0; i < numTimeBins; ++i) {
			for (int16_t x = -1; x <= 1; ++x) {
				for (int16_t y = -1; y <= 1; ++y) {
					store.emplace_back(initialTimestamp + (timeDelta * i), (resolution.width / 2) + x,
						(resolution.height / 2) + y, true);
				}
			}
		}

		filter.accept(store);
		const dv::EventStore filteredEvents = filter.generateEvents();

		// Note: since only the last columns and rows are stored, the square of size numSupportingPixels *
		// numSupportingPixels is discarded for all time
		const size_t discardedSize = numTimeBins;
		expect(eq(filteredEvents.size(), store.size() - discardedSize));
	};

	return EXIT_SUCCESS;
}
