// =============================================================================
//  protocols/nmea0183_parser.cpp -- $PARP sentence parser
// =============================================================================

#include "nmea0183_parser.h"

#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <Arduino.h>

namespace arconcentrador::protocols {

// ---------------------------------------------------------------------------
uint8_t nmea_checksum(const char* sentence) {
    // Find content between '$' and '*'
    const char* start = strchr(sentence, '$');
    if (!start) return 0xFF;
    start++;  // skip '$'
    const char* end = strchr(start, '*');
    if (!end) return 0xFF;
    uint8_t crc = 0;
    for (const char* p = start; p < end; ++p) crc ^= (uint8_t)*p;
    return crc;
}

// ---------------------------------------------------------------------------
ParpCommand parp_parse(const char* sentence) {
    ParpCommand result{};
    result.valid = false;

    // Must start with $PARP,
    if (strncmp(sentence, "$PARP,", 6) != 0) return result;

    // Validate checksum
    const char* star = strchr(sentence, '*');
    if (!star || strlen(star) < 3) return result;
    const uint8_t recv_crc  = (uint8_t)strtoul(star + 1, nullptr, 16);
    const uint8_t calc_crc  = nmea_checksum(sentence);
    if (recv_crc != calc_crc) {
        Serial.printf("[PARSER] checksum error: recv=%02X calc=%02X\n",
                      recv_crc, calc_crc);
        return result;
    }

    // Copy body between "$PARP," and '*'
    char body[128];
    const char* body_start = sentence + 6;
    const size_t body_len  = (size_t)(star - body_start);
    if (body_len == 0 || body_len >= sizeof(body)) return result;
    memcpy(body, body_start, body_len);
    body[body_len] = '\0';

    // Tokenize: CMD,VALUE,STATION_ID
    char* saveptr = nullptr;
    const char* tok_cmd = strtok_r(body, ",", &saveptr);
    const char* tok_val = strtok_r(nullptr, ",", &saveptr);
    const char* tok_sta = strtok_r(nullptr, ",", &saveptr);

    if (!tok_cmd || !tok_val || !tok_sta) return result;

    strncpy(result.cmd, tok_cmd, sizeof(result.cmd) - 1);
    result.value      = (float)atof(tok_val);
    result.station_id = (uint8_t)atoi(tok_sta);

    if (result.station_id < 1 || result.station_id > 4) return result;

    result.valid = true;
    return result;
}

// ---------------------------------------------------------------------------
static char s_line_buf[256];
static size_t s_line_len = 0;

bool parp_feed(char c, ParpCommand& out) {
    if (c == '$') {
        // Start of new sentence — reset buffer.
        s_line_len = 0;
    }
    if (s_line_len < sizeof(s_line_buf) - 1) {
        s_line_buf[s_line_len++] = c;
    }
    if (c == '\n') {
        s_line_buf[s_line_len] = '\0';
        s_line_len = 0;
        out = parp_parse(s_line_buf);
        return out.valid;
    }
    return false;
}

}  // namespace arconcentrador::protocols
