#ifndef LINUX_DEVICES_MAX31865RTDREADER_H_
#define LINUX_DEVICES_MAX31865RTDREADER_H_

#include <fsfw/ipc/MutexIF.h>
#include <fsfw/tasks/ExecutableObjectIF.h>
#include <fsfw_hal/linux/spi/SpiComIF.h>
#include <fsfw_hal/linux/spi/SpiCookie.h>

#include "fsfw/devicehandlers/DeviceCommunicationIF.h"
#include "mission/devices/devicedefinitions/Max31865Definitions.h"

struct Max31865ReaderCookie : public CookieIF {
  Max31865ReaderCookie(){};
  Max31865ReaderCookie(object_id_t handlerId_, uint8_t idx_, const std::string& locString_,
                       SpiCookie* spiCookie_)
      : idx(idx_), handlerId(handlerId_), locString(locString_), spiCookie(spiCookie_) {}

  uint8_t idx = 0;
  object_id_t handlerId = objects::NO_OBJECT;

  std::string locString = "";
  std::array<uint8_t, 12> exchangeBuf{};
  Countdown cd = Countdown(MAX31865::WARMUP_MS);

  bool on = false;
  bool configured = false;
  bool active = false;
  bool writeLowThreshold = false;
  bool writeHighThreshold = false;
  uint16_t lowThreshold = 0;
  uint16_t highThreshold = 0;
  SpiCookie* spiCookie = nullptr;

  // Exchange data buffer struct
  EiveMax31855::ReadOutStruct db;
};

class Max31865RtdReader : public SystemObject,
                          public ExecutableObjectIF,
                          public DeviceCommunicationIF {
 public:
  Max31865RtdReader(object_id_t objectId, SpiComIF* lowLevelComIF, GpioIF* gpioIF);

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

 private:
  std::vector<Max31865ReaderCookie*> rtds;
  std::array<uint8_t, 4> cmdBuf = {};
  size_t dbLen = 0;
  MutexIF* readerMutex;

  SpiComIF* comIF;
  GpioIF* gpioIF;
  MutexIF::TimeoutType csTimeoutType = MutexIF::TimeoutType::BLOCKING;
  uint32_t csTimeoutMs = 0;
  MutexIF* csLock = nullptr;

  bool periodicInitHandling();
  ReturnValue_t periodicReadReqHandling();
  ReturnValue_t periodicReadHandling();

  bool rtdIsActive(uint8_t idx);
  ReturnValue_t writeCfgReg(SpiCookie* cookie, uint8_t cfg);
  ReturnValue_t writeBiasSel(MAX31865::Bias bias, SpiCookie* cookie, uint8_t baseCfg);
  ReturnValue_t readCfgReg(SpiCookie* cookie, uint8_t& cfg);
  ReturnValue_t readRtdVal(SpiCookie* cookie, uint16_t& val, bool& faultBitSet);
  ReturnValue_t writeLowThreshold(SpiCookie* cookie, uint16_t val);
  ReturnValue_t writeHighThreshold(SpiCookie* cookie, uint16_t val);
  ReturnValue_t readLowThreshold(SpiCookie* cookie, uint16_t& val);
  ReturnValue_t readHighThreshold(SpiCookie* cookie, uint16_t& val);
  ReturnValue_t clearFaultStatus(SpiCookie* cookie);

  ReturnValue_t readNFromReg(SpiCookie* cookie, uint8_t reg, size_t n, uint8_t** reply);
  ReturnValue_t writeNToReg(SpiCookie* cookie, uint8_t reg, size_t n, uint8_t* cmd,
                            uint8_t** reply);

  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;

  ReturnValue_t handleSpiError(Max31865ReaderCookie* cookie, ReturnValue_t result, const char* ctx);
};

#endif /* LINUX_DEVICES_MAX31865RTDREADER_H_ */