#pragma once

#include <stddef.h>
#include <stdint.h>

constexpr size_t METER_FRAME_MAX = 512;
constexpr uint8_t METER_REQUIRED_FIELDS_MASK = 0x1f;

enum class MeterFrameEvent : uint8_t {
  None = 0,
  Complete,
  Timeout,
  Overflow,
  Resync
};

struct MeterFrameCollector {
  char buffer[METER_FRAME_MAX + 1];
  size_t length;
  uint32_t last_rx_ms;
  bool in_frame;
};

void meter_frame_collector_init(MeterFrameCollector &collector);
MeterFrameEvent meter_frame_collector_check_timeout(MeterFrameCollector &collector,
                                                     uint32_t now_ms,
                                                     uint32_t timeout_ms);
MeterFrameEvent meter_frame_collector_feed(MeterFrameCollector &collector,
                                            char byte,
                                            uint32_t now_ms);

enum class MeterParseStatus : uint8_t {
  Valid = 0,
  Empty,
  MissingTerminator,
  LineTooLong,
  MissingRequired,
  InvalidMeterSeconds,
  MalformedValue
};

struct MeterParseResult {
  float energy_total_kwh;
  float total_power_w;
  float phase_power_w[3];
  uint32_t meter_seconds;
  uint8_t fields_mask;
  bool meter_seconds_valid;
  bool valid;
  MeterParseStatus status;
};

bool meter_parser_parse(const char *frame, size_t len, MeterParseResult &result);
const char *meter_parse_status_text(MeterParseStatus status);
