#ifndef CONFIGURATION_H
#define CONFIGURATION_H

// clang-tidy off
// clang-format off
#include "json.hpp"
// clang-format on
// clang-tidy on
#include "rosa/config/version.h"
#include "rosa/app/Application.hpp"
#include <fstream>

using namespace rosa;
using nlohmann::json;

struct SignalConfiguration {
  std::string Name;
  std::string InputPath;
  bool Output;
  float InnerBound;
  float OuterBound;
  float InnerBoundDrift;
  float OuterBoundDrift;
  uint32_t SampleHistorySize;
  uint32_t DABSize;
  uint32_t DABHistorySize;
};

struct AppConfiguration {
  std::string OutputFilePath;
  uint32_t BrokenCounter;
  uint32_t NumberOfSimulationCycles;
  uint32_t DownsamplingRate;
  std::vector<SignalConfiguration> SignalConfigurations;
};

void from_json(const json &J, SignalConfiguration &SC) {
  J.at("Name").get_to(SC.Name);
  J.at("InputPath").get_to(SC.InputPath);
  J.at("Output").get_to(SC.Output);
  J.at("InnerBound").get_to(SC.InnerBound);
  J.at("OuterBound").get_to(SC.OuterBound);
  J.at("InnerBoundDrift").get_to(SC.InnerBoundDrift);
  J.at("OuterBoundDrift").get_to(SC.OuterBoundDrift);
  J.at("SampleHistorySize").get_to(SC.SampleHistorySize);
  J.at("DABSize").get_to(SC.DABSize);
  J.at("DABHistorySize").get_to(SC.DABHistorySize);
}

void from_json(const json &J, AppConfiguration &AC) {
  J.at("OutputFilePath").get_to(AC.OutputFilePath);
  J.at("BrokenCounter").get_to(AC.BrokenCounter);
  J.at("NumberOfSimulationCycles").get_to(AC.NumberOfSimulationCycles);
  J.at("DownsamplingRate").get_to(AC.DownsamplingRate);
  J.at("SignalConfigurations").get_to(AC.SignalConfigurations);
}

AppConfiguration AppConfig;

bool readConfigFile(std::string ConfigPath) {

  LOG_INFO("READING CONFIG FILE");
  LOG_INFO_STREAM << "Looking for config file at \"" << ConfigPath << "\"\n";

  std::ifstream ConfigFile;
  ConfigFile.open(ConfigPath);

  if (!ConfigFile) {
    LOG_ERROR("Unable to open config file");
    return false;
  }

  json ConfigObj;
  ConfigFile >> ConfigObj;
  LOG_INFO_STREAM << "Read JSON file as \"" << ConfigObj << "\"\n";

  try {
    ConfigObj.get_to(AppConfig);
  } catch (nlohmann::detail::type_error ex) {
    LOG_ERROR("Misformatted Config File");
    return false;
  }

  return true;
}

#endif // CONFIGURATION_H
