#pragma once

#include "../../../include/dv-processing/io/camera/dvs128.hpp"

#include <pybind11/pybind11.h>

namespace py = pybind11;

/**
 * @brief Bind discoverDevices class to python
 * @param m pybind The module to bind to
 */
void bind_dvs128(py::module &m) {
	static dv::io::camera::USBDevice::loggerCallbackType DEFAULT_CLI_LOGGER
		= [](const dv::io::camera::USBDevice::LogLevel level, const std::string_view deviceName,
			  const std::string_view message) {
			  std::cerr << fmt::format("[{}] {}: {}", level, deviceName, message) << std::endl;
		  };

	py::class_<dv::io::camera::DVS128, dv::io::camera::USBDevice, dv::io::camera::SyncCameraInputBase> dvs128(
		m, "DVS128", "DVS128 camera.");

	py::enum_<dv::io::camera::DVS128::Bias>(dvs128, "Bias")
		.value("CAS", dv::io::camera::DVS128::Bias::CAS)
		.value("INJGND", dv::io::camera::DVS128::Bias::INJGND)
		.value("REQPD", dv::io::camera::DVS128::Bias::REQPD)
		.value("PUX", dv::io::camera::DVS128::Bias::PUX)
		.value("DIFF_OFF", dv::io::camera::DVS128::Bias::DIFF_OFF)
		.value("REQ", dv::io::camera::DVS128::Bias::REQ)
		.value("REFR", dv::io::camera::DVS128::Bias::REFR)
		.value("PUY", dv::io::camera::DVS128::Bias::PUY)
		.value("DIFF_ON", dv::io::camera::DVS128::Bias::DIFF_ON)
		.value("DIFF", dv::io::camera::DVS128::Bias::DIFF)
		.value("FOLL", dv::io::camera::DVS128::Bias::FOLL)
		.value("PR", dv::io::camera::DVS128::Bias::PR);

	dvs128.def_static(
		"findDevices",
		[](const std::string_view filterBySerialNumber) {
			return dv::io::camera::DVS128::findDevices(filterBySerialNumber, DEFAULT_CLI_LOGGER);
		},
		py::arg("filterBySerialNumber") = "", "Find connected DVS128 cameras.");

	dvs128
		.def(py::init([](const dv::io::camera::USBDevice::LogLevel deviceLogLevel) {
			return std::make_unique<dv::io::camera::DVS128>(DEFAULT_CLI_LOGGER, deviceLogLevel);
		}),
			py::arg("deviceLogLevel") = dv::io::camera::USBDevice::LogLevel::LVL_WARNING,
			"Open the first DVS128 camera that can be found.")
		.def(py::init([](const std::string_view filterBySerialNumber,
						  const dv::io::camera::USBDevice::LogLevel deviceLogLevel) {
			return std::make_unique<dv::io::camera::DVS128>(filterBySerialNumber, DEFAULT_CLI_LOGGER, deviceLogLevel);
		}),
			py::arg("filterBySerialNumber"),
			py::arg("deviceLogLevel") = dv::io::camera::USBDevice::LogLevel::LVL_WARNING,
			"Open the DVS128 camera with the specified serial number.")
		.def(py::init([](const dv::io::camera::USBDevice::DeviceDescriptor &deviceToOpen,
						  const dv::io::camera::USBDevice::LogLevel deviceLogLevel) {
			return std::make_unique<dv::io::camera::DVS128>(deviceToOpen, DEFAULT_CLI_LOGGER, deviceLogLevel);
		}),
			py::arg("deviceToOpen"), py::arg("deviceLogLevel") = dv::io::camera::USBDevice::LogLevel::LVL_WARNING,
			"Open the DVS128 camera corresponding to the specified descriptor.")
		.def("setMaster", &dv::io::camera::DVS128::setMaster, py::arg("master"),
			"Control clock master functionality of this camera.")
		.def("getBias", &dv::io::camera::DVS128::getBias, py::arg("bias"),
			"Get current value of specified bias configuration.")
		.def("setBias", &dv::io::camera::DVS128::setBias, py::arg("bias"), py::arg("value"),
			"Set new value for specified bias configuration.");
}
