#include "pch.h"
#include "XYParserApi.h"

#include <array>
#include <cstdint>
#include <vector>

namespace {

std::vector<std::uint8_t> BuildMinimalFrame(std::uint8_t channel_count)
{
    constexpr std::size_t kSamplesPerFrame = 5;
    constexpr std::uint8_t kHeader = 0xAA;
    constexpr std::uint8_t kTail = 0x55;
    constexpr std::size_t kTagLen = 25;

    const std::size_t sample_bytes = static_cast<std::size_t>(channel_count) * 3 + 2;
    const std::uint16_t payload_length = static_cast<std::uint16_t>(sample_bytes * kSamplesPerFrame);
    const std::size_t frame_size = 1 + kTagLen + payload_length + 2;

    std::vector<std::uint8_t> frame(frame_size, 0);
    std::size_t offset = 0;

    frame[offset++] = kHeader;

    // index, little endian
    frame[offset++] = 0x01;
    frame[offset++] = 0x00;
    frame[offset++] = 0x00;
    frame[offset++] = 0x00;

    // payload length, big endian
    frame[offset++] = static_cast<std::uint8_t>((payload_length >> 8) & 0xFF);
    frame[offset++] = static_cast<std::uint8_t>(payload_length & 0xFF);

    frame[offset++] = 95;             // battery
    frame[offset++] = channel_count;  // channelCount

    // elevation / roll / yaw / ecg / spo2 / reserved[6]
    offset += 2 + 2 + 2 + 2 + 2 + 6;

    // Build 5 samples. Each channel uses 3 ADC bytes, followed by trigger fields.
    for (std::size_t sample = 0; sample < kSamplesPerFrame; ++sample) {
        for (std::size_t channel = 0; channel < channel_count; ++channel) {
            frame[offset++] = 0x00;
            frame[offset++] = 0x00;
            frame[offset++] = static_cast<std::uint8_t>(sample + channel + 1);
        }
        frame[offset++] = 0x00; // triggerType
        frame[offset++] = 0x00; // triggerIndex
    }

    frame[offset++] = 0x00; // crc, ignored when bypass checksum is enabled
    frame[offset++] = kTail;
    frame[offset++] = kTail;

    return frame;
}

} // namespace

void MinimalExampleFor8ChParser()
{
    XYParserHandle parser = XYParser_CreateParser(8);
    if (parser == nullptr) {
        return;
    }
    XYParser_SetAdcParams(parser, 4.5, 6.0);
    XYParser_SetBypassChecksum(parser, 1);

    const std::vector<std::uint8_t> raw_bytes = BuildMinimalFrame(8);
    std::array<XYParserFrameSummary, 1> summaries{};
    const int frame_count = XYParser_Feed(parser,
                                          raw_bytes.data(),
                                          raw_bytes.size(),
                                          summaries.data(),
                                          static_cast<int>(summaries.size()));

    if (frame_count > 0) {
        const XYParserFrameSummary& frame = summaries.front();
        const double first_channel_uv = frame.channel_values_uv[0][0];
        (void)first_channel_uv;
    }

    XYParser_DestroyParser(parser);
}

void MinimalExampleFor64ChParser()
{
    XYParserHandle parser = XYParser_CreateParser(64);
    if (parser == nullptr) {
        return;
    }
    XYParser_SetAdcParams(parser, 4.5, 6.0);
    XYParser_SetBypassChecksum(parser, 1);

    const std::vector<std::uint8_t> raw_bytes = BuildMinimalFrame(64);
    std::array<XYParserFrameSummary, 1> summaries{};
    const int frame_count = XYParser_Feed(parser,
                                          raw_bytes.data(),
                                          raw_bytes.size(),
                                          summaries.data(),
                                          static_cast<int>(summaries.size()));

    if (frame_count > 0) {
        const XYParserFrameSummary& frame = summaries.front();
        const std::uint8_t battery = frame.battery;
        (void)battery;
    }

    XYParser_DestroyParser(parser);
}
