#pragma once

#include <driver/gpio.h>
#include <driver/spi_master.h>
#include <stdint.h>

#define SX127_MAX_PACKET_LEN 255

// carrier frequency type
typedef uint64_t sx127x_freq_t;

#define SX127X_FREQ_433 ((sx127x_freq_t)433E6)
#define SX127X_FREQ_915 ((sx127x_freq_t)915E6)

// signal bandwidth type
typedef uint64_t sx127x_bw_t;
// spreading factor type
typedef uint8_t sx127x_sf_t;

typedef enum sx127x_pa_boost {
  SX127X_PA_BOOST_DISABLED = 0,
  SX127X_PA_BOOST_ENABLED  = 1,
} sx127x_pa_boost_t;

typedef enum sx127x_crc {
  SX127X_CRC_DISABLED = 0,
  SX127X_CRC_ENABLED  = 1,
} sx127x_crc_t;

// low data rate optimization
typedef enum sx127x_ldo {
  SX127X_LDO_DISABLED = 0,
  SX127X_LDO_ENABLED  = 1,
} sx127x_ldo_t;

typedef struct sx127x_config {
  spi_host_device_t spi_host;
  gpio_num_t        mosi_io_num;
  gpio_num_t        miso_io_num;
  gpio_num_t        sck_io_num;
  gpio_num_t        cs_io_num;
  gpio_num_t        rst_io_num;
  gpio_num_t        irq_io_num;
  uint8_t           tx_power;
  sx127x_freq_t     frequency;
  sx127x_bw_t       signal_bandwidth;
  sx127x_sf_t       spreading_factor;
  uint8_t           sync_word;
  sx127x_crc_t      crc;
  sx127x_ldo_t      ldo;
} sx127x_config_t;

// clang-format off
#define SX127X_CONFIG_DEFAULT     \
  {                               \
    .spi_host = VSPI_HOST,        \
    .mosi_io_num = 27,            \
    .miso_io_num = 19,            \
    .sck_io_num = 5,              \
    .cs_io_num = 18,              \
    .rst_io_num = 14,             \
    .irq_io_num = 26,             \
    .tx_power = 17,               \
    .frequency = SX127X_FREQ_433, \
    .signal_bandwidth = 125E3,    \
    .spreading_factor = 11,       \
    .sync_word = 0x34,            \
    .crc = SX127X_CRC_ENABLED,    \
    .ldo = SX127X_LDO_DISABLED    \
  }
// clang-format on

typedef struct sx127x_packet_rx {
  char *  data;
  size_t  data_len;
  // rssi value
  int32_t rssi;
  // snr value in steps of .25
  int8_t  snr;
} sx127x_rx_packet_t;

typedef struct sx127x* sx127x_hndl;

sx127x_config_t sx127x_config_default();

esp_err_t sx127x_init(const sx127x_config_t *config, sx127x_hndl *hndl_ptr);

esp_err_t sx127x_free(sx127x_hndl hndl);

esp_err_t sx127x_start(sx127x_hndl hndl);

esp_err_t sx127x_stop(sx127x_hndl hndl);

esp_err_t sx127x_send_packet(sx127x_hndl hndl, const char *data,
                             size_t data_len, TickType_t ticks_to_wait);

esp_err_t sx127x_recv_packet(sx127x_hndl hndl, sx127x_rx_packet_t *packet_out,
                             TickType_t ticks_to_wait);

QueueHandle_t sx127x_get_recv_queue(sx127x_hndl hndl);

void sx127x_packet_rx_free(sx127x_rx_packet_t *packet);