#pragma once

#include "StreamingMsgPackEncoder.h"
#include <cstdint>

template <typename Measurement_T, uint32_t SIZE>
class SessionChunk
{
public:
    SessionChunk()
        : nextFree_(0), sessionStartTime(0), startIndex(0)
    {
    }

    void init(uint32_t epochStartTime, uint32_t startIdx)
    {
        nextFree_ = 0;
        sessionStartTime = epochStartTime;
        startIndex = startIdx;
    }

    uint32_t getStartTime() const
    {
        return sessionStartTime;
    }

    uint32_t getStartIndex() const
    {
        return startIndex;
    }

    uint32_t numMeasurements() const
    {
        return nextFree_;
    }

    bool addPoint(Measurement_T measurement)
    {
        if (nextFree_ >= SIZE)
            return false;
        values[nextFree_] = measurement;
        nextFree_++;

        return true;
    }

    template <typename T>
    void serialize(StreamingMsgPackEncoder<T> &encoder) const
    {
        sendHeader(encoder, sessionStartTime, startIndex);
        encoder.sendArray(values, nextFree_);
    }

    static uint32_t valueOffset()
    {
        StreamingMsgPackEncoder<DummyWriter> encoder(nullptr);
        encoder.setSizeCountMode(true);
        sendHeader(encoder, 0, 0);
        encoder.template sendArrayHeader<Measurement_T>(0);
        return encoder.getContentLength();
    }

    static uint32_t arrayHeaderOffset()
    {
        StreamingMsgPackEncoder<DummyWriter> encoder(nullptr);
        encoder.setSizeCountMode(true);
        sendHeader(encoder, 0, 0);
        return encoder.getContentLength();
    }

    Measurement_T *getDataPointer()
    {
        return values;
    }

    const Measurement_T *getDataPointer() const
    {
        return values;
    }

    template <typename Encoder_T>
    static void sendHeader(Encoder_T &encoder, uint32_t sessionStartTime, uint32_t startIndex)
    {
        encoder.sendMap16(3);

        encoder.sendString255("sessionStartTime");
        encoder.sendInt(sessionStartTime);

        encoder.sendString255("startIndex");
        encoder.sendInt(startIndex);

        encoder.sendString255("values");
    }

private:
    uint32_t nextFree_ = 0;
    uint32_t sessionStartTime;
    uint32_t startIndex;
    Measurement_T values[SIZE];
};