#ifndef LINUX_DEVICES_IMTQPOLLINGTASK_H_
#define LINUX_DEVICES_IMTQPOLLINGTASK_H_

#include <fsfw/tasks/SemaphoreIF.h>
#include <fsfw_hal/linux/i2c/I2cCookie.h>

#include "fsfw/devicehandlers/DeviceCommunicationIF.h"
#include "fsfw/objectmanager/SystemObject.h"
#include "fsfw/tasks/ExecutableObjectIF.h"
#include "mission/devices/devicedefinitions/imtqHelpers.h"

class ImtqPollingTask : public SystemObject,
                        public ExecutableObjectIF,
                        public DeviceCommunicationIF {
 public:
  ImtqPollingTask(object_id_t imtqPollingTask);

  ReturnValue_t performOperation(uint8_t operationCode) override;
  ReturnValue_t initialize() override;

 private:
  static constexpr ReturnValue_t NO_REPLY_AVAILABLE = returnvalue::makeCode(2, 0);

  enum class InternalState { IDLE, BUSY } state = InternalState::IDLE;
  imtq::RequestType currentRequest = imtq::RequestType::MEASURE_NO_ACTUATION;

  SemaphoreIF* semaphore;
  ReturnValue_t comStatus = returnvalue::OK;
  MutexIF* ipcLock;
  MutexIF* bufLock;
  I2cCookie* i2cCookie = nullptr;
  const char* i2cDev = nullptr;
  address_t i2cAddr = 0;
  uint32_t currentIntegrationTimeMs = 10;
  // Required in addition to integration time, otherwise old data might be read.
  static constexpr uint32_t MGM_READ_BUFFER_TIME_MS = 6;
  bool ignoreNextActuateRequest = false;

  imtq::SpecialRequest specialRequest = imtq::SpecialRequest::NONE;
  int16_t dipoles[3] = {};
  uint16_t torqueDuration = 0;

  std::array<uint8_t, 32> cmdBuf;
  std::array<uint8_t, 524> replyBuf;
  std::array<uint8_t, 524> replyBufActuation;
  std::array<uint8_t, 524> exchangeBuf;
  size_t cmdLen = 0;

  // DeviceCommunicationIF overrides
  ReturnValue_t initializeInterface(CookieIF* cookie) override;
  ReturnValue_t sendMessage(CookieIF* cookie, const uint8_t* sendData, size_t sendLen) override;
  ReturnValue_t getSendSuccess(CookieIF* cookie) override;
  ReturnValue_t requestReceiveMessage(CookieIF* cookie, size_t requestLen) override;
  ReturnValue_t readReceivedMessage(CookieIF* cookie, uint8_t** buffer, size_t* size) override;

  void ccToReplyPtrMeasure(ImtqRepliesDefault& replies, imtq::CC::CC cc, uint8_t** replyBuf,
                           size_t& replyLen);
  void ccToReplyPtrActuate(ImtqRepliesWithTorque& replies, imtq::CC::CC cc, uint8_t** replyBuf,
                           size_t& replyLen);
  void clearReadFlagsDefault(ImtqRepliesDefault& replies);
  void clearReadFlagsWithTorque(ImtqRepliesWithTorque& replies);
  size_t getExchangeBufLen(imtq::SpecialRequest specialRequest);
  void buildDipoleCommand();
  void handleMeasureStep();
  void handleActuateStep();
  ReturnValue_t i2cCmdExecDefault(imtq::CC::CC cc, uint8_t* replyPtr, size_t replyLen,
                                  ReturnValue_t comErrIfFails);
  ReturnValue_t performI2cFullRequest(uint8_t* reply, size_t replyLen);
};

#endif /* LINUX_DEVICES_IMTQPOLLINGTASK_H_ */