#pragma once

#include <ArduinoJson.h>
#include "MeasurementData.hpp"
#include "SensorProtocol.hpp"
#include "SensorInformation.hpp"
#include <list>
#include <optional>
#include <string>
#include <utility>
#include <ErrorTypes.h>

// having the data be a struct of basic types makes sending easier,
// otherwise we would have to serialize the data before sending
class ClientDataPackage {
 private:
  MeasurementData measurementData;
  SensorInformation sensorInformation;
  ErrorType errorType;
  unsigned long timestamp; // maybe make this array

 public:
  ClientDataPackage(MeasurementData value,
                    SensorInformation sensorInformation,
                    ErrorType errorType,
                    unsigned long timestamp)
      : measurementData(value),
        sensorInformation(sensorInformation),
        timestamp(timestamp),
        errorType(errorType) {
  }


  [[nodiscard]] ErrorType getErrorType() const {
    return errorType;
  }

  void setErrorType(ErrorType error) {
    ClientDataPackage::errorType = error;
  }

  [[nodiscard]] const MeasurementData &
  getMeasurementData() const { return measurementData; }

  [[nodiscard]] const SensorInformation &
  getSensorInformation() const { return sensorInformation; }

  [[nodiscard]] unsigned long getTimestamp() const { return timestamp; }

  [[nodiscard]] std::string getDataPackageAsMinifiedJsonString() const {
    StaticJsonDocument<250> document; // 250 byte is the max send size of espnow

    document["hardwareName"] = sensorInformation.getHardwareNameString();
    document["timestamp"] = timestamp;
    document["sensorProtocol"] = sensorInformation.getProtocolString();
    document["value"] = measurementData.getValue();


    document["channel"] = measurementData.getChannel();


    document["i2cAddress"] = measurementData.getI2CAddress();

    document["measurementType"] = measurementData.getMeasurementTypeString();

    std::string jsonString;
    serializeJson(document, jsonString);
    return jsonString;
  }

  ClientDataPackage() : measurementData(MeasurementData(ERROR_VALUE,
                                                        MeasurementType::TEMPERATURE)),
                        sensorInformation(SensorInformation(HardwareName::NONE,
                                                            SensorProtocol::NULL_PROTOCOL)),
                        timestamp(0),
                        errorType(ErrorType::NO_DATA) {}
};