#pragma once

#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
#include <freertos/task.h>

#include "messages.pb.h"

#ifdef COMMS_SX127X
#include "sx127x_driver.h"
#else
#include "e32_driver.hh"
#endif

namespace ugv {
namespace comms {

namespace messages = ugv::messages;
namespace config = ugv::config;

class CommsClass {
 public:
  static constexpr int MAX_PACKET_LEN = 128;
  static constexpr TickType_t PACKET_RX_TIMEOUT = pdMS_TO_TICKS(200);

  CommsClass();

  void Init();

  void Lock(TickType_t ticks_to_wait = pdMS_TO_TICKS(1000));
  void Unlock();

  int32_t ReadRssi();
  uint8_t ReadLnaGain();

 public:
  SemaphoreHandle_t mutex;
  TickType_t last_packet_tick;
  int32_t last_packet_rssi;
  int8_t last_packet_snr;

  messages::UGV_Status status;
  messages::DriveHeadingData drive_heading;
  messages::TargetLocation* new_target;
  config::Config* new_config;

 private:
#ifdef COMMS_SX127X
  sx127x_hndl lora;
#else
  e32::E32_Driver lora;
#endif
  TaskHandle_t task_handle;

  messages::UGV_Message status_message;
  std::string status_message_data;
  TickType_t next_status_send;

  void RunTask();

#ifdef COMMS_SX127X
  void HandlePacket(sx127x_rx_packet_t* packet);
#endif

  void HandlePacket(const uint8_t* data, size_t size);
  void HandleCommand(const messages::GroundCommand& command);

  esp_err_t SendPacket(const uint8_t* data, size_t size);
  esp_err_t SendPacket(const std::string& str);
  esp_err_t SendPacket(const google::protobuf::MessageLite& message);

  void SendStatus();

  static void CommsTask(void* arg);
};

}  // namespace comms
}  // namespace ugv