#pragma once

#include "../../../include/dv-processing/core/time.hpp"
#include "../../../include/dv-processing/data/imu_base.hpp"

#include <pybind11/pybind11.h>
#include <pybind11/stl_bind.h>

PYBIND11_MAKE_OPAQUE(std::vector<dv::IMU>)

namespace py = pybind11;

/**
 * @brief Bind IMU class to python
 * @param m pybind The module to bind to
 */
void bind_imu_base(py::module &m) {
	using pybind11::operator""_a;

	// Bind dv::IMU
	py::class_<dv::IMU>(m, "IMU")
		.def(py::init<int64_t, float, float, float, float, float, float, float, float, float, float>(),
			py::arg("timestamp"), py::arg("temperature"), py::arg("accelerometerX"), py::arg("accelerometerY"),
			py::arg("accelerometerZ"), py::arg("gyroscopeX"), py::arg("gyroscopeY"), py::arg("gyroscopeZ"),
			py::arg("magnetometerX"), py::arg("magnetometerY"), py::arg("magnetometerZ"))
		.def_readwrite("timestamp", &dv::IMU::timestamp, "Unix microsecond timestamp of the captured IMU data")
		.def_readwrite("temperature", &dv::IMU::temperature, "Temperature, measured in °C.")
		.def_readwrite(
			"accelerometerX", &dv::IMU::accelerometerX, "Acceleration in the X axis, measured in g (9.81m/s²).")
		.def_readwrite(
			"accelerometerY", &dv::IMU::accelerometerY, "Acceleration in the Y axis, measured in g (9.81m/s²).")
		.def_readwrite(
			"accelerometerZ", &dv::IMU::accelerometerZ, "Acceleration in the Z axis, measured in g (9.81m/s²).")
		.def_readwrite("gyroscopeX", &dv::IMU::gyroscopeX, "Rotation in the X axis, measured in °/s.")
		.def_readwrite("gyroscopeY", &dv::IMU::gyroscopeY, "Rotation in the Y axis, measured in °/s.")
		.def_readwrite("gyroscopeZ", &dv::IMU::gyroscopeZ, "Rotation in the Z axis, measured in °/s.")
		.def_readwrite(
			"magnetometerX", &dv::IMU::magnetometerX, "Magnetometer X axis, measured in µT (magnetic flux density).")
		.def_readwrite(
			"magnetometerY", &dv::IMU::magnetometerY, "Magnetometer Y axis, measured in µT (magnetic flux density).")
		.def_readwrite(
			"magnetometerZ", &dv::IMU::magnetometerZ, "Magnetometer Z axis, measured in µT (magnetic flux density).")
		.def(
			"time",
			[](const dv::IMU &self) {
				return dv::toTimePoint(self.timestamp);
			},
			"Timestamp of the captured data, compatible with python time library")
		.def("getAccelerations", &dv::IMU::getAccelerations, "Get measured acceleration in m/s².")
		.def("getAngularVelocities", &dv::IMU::getAngularVelocities, "Get measured angular velocities in rad/s.");

	// Bind dv::IMUPacket
	py::class_<dv::IMUPacket> imuPacketClass(m, "IMUPacket");
	py::bind_vector<std::vector<dv::IMU>>(imuPacketClass, "ImuVector");

	imuPacketClass.def(py::init<>())
		.def(py::init<const std::vector<dv::IMU> &>(), "imu_measurements"_a,
			"Create a packet from a list of IMU measurements")
		.def_readwrite("elements", &dv::IMUPacket::elements)
		.def_static("GetFullyQualifiedName", &dv::IMUPacket::GetFullyQualifiedName)
		.def_static("PacketIdentifier", &dv::IMUPacketIdentifier);

	py::implicitly_convertible<std::vector<dv::IMU>, dv::IMUPacket>();
}
