#include "Controller.h"


#ifdef BUILD_TARGET_SOM
#include "application/AppLogic.hpp"
#include "application/Environment.hpp"
#include "application/EventLogger.hpp"
#include "deviceConfig/model/DeviceConfiguration.hpp"
#include "deviceConfig/model/state/GuardedAnalogConfiguration.hpp"
#include "state/DeviceState.hpp"



bool Controller::initialize(const char *configFilePath, appengine::IAppLogic *appLogic) {
  appLogic_ = appLogic;
  auto deviceState = appLogic->deviceState();




  // Beispiel:
  SV_Temperatur_Variable_               = deviceState.getVariableByKey("Temperatur_Innenraum");
  SV_Feuchte_Variable_                  = deviceState.getVariableByKey("Humidity");
  SV_Tuer_Variable_                     = deviceState.getVariableByKey("Temperatur_Tuer");
  Wasserstand_Oben_Config_              = deviceState.getVariableByKey("Wasserstand_Hoch");
  Wasserstand_Unten_Config_             = deviceState.getVariableByKey("Wasserstand_Tief");
  Fuellstand_Config_                    = deviceState.getVariableByKey("Fuellstand");
  Heizung_Bef_Config_                   = deviceState.getVariableByKey("Heizung_Bef");
  MV_Kuehlung_Config_                   = deviceState.getVariableByKey("MV_Kuehlung");
  Abschlaemmen_Config_                  = deviceState.getVariableByKey("Abschlaemmen");
  Entleerpumpe_Config_                  = deviceState.getVariableByKey("Entleerpumpe");
  Heizung_Kesselrand_Config_            = deviceState.getVariableByKey("Heizung_Kesselrand");
  Freigabe_Verfluessigerluefter_Config_ = deviceState.getVariableByKey("Freigabe_Verfluessigerluefter");
  Heizung_Innenraum_Config_             = deviceState.getVariableByKey("Heizung_Innenraum");
  Heizung_Tuer_Config_                  = deviceState.getVariableByKey("Heizung_Tuer");
  Uebertemperatur_Config_               = deviceState.getVariableByKey("Uebertemperatur");
  MV_Entfeuchtung_Config_               = deviceState.getVariableByKey("MV_Entfeuchtung");
  MV_Druckluft_Config_                  = deviceState.getVariableByKey("MV_Druckluft");
  Ansteuerung_Wassereinlass_Config_     = deviceState.getVariableByKey("Ansteuerung_Wassereinlass");
  Ansteuerung_Verdichter_Config_        = deviceState.getVariableByKey("Ansteuerung_Verdichter");
  Luefter_Innenraum_Config_             = deviceState.getVariableByKey("Luefter_Innenraum");
  SV_Verdampferausgang_                 = deviceState.getVariableByKey("Temperatur_Verdampferausgang");
  SV_Befeuchtungsmodul_                 = deviceState.getVariableByKey("Temperatur_Befeuchtungsmodul");
  const_duty_cycle_                     = deviceState.getVariableByKey("steady_duty");
  const_freq_                           = deviceState.getVariableByKey("steady_freq");
  Verdichter_Duty_Config                = deviceState.getVariableByKey("Ansteuerung_Verdichter_duty");
  SV_Stellgrad_Heizung                  = deviceState.getVariableByKey("Stellgrad_Heizung");
  SV_Stellgrad_Kuehlung                 = deviceState.getVariableByKey("Stellgrad_Kuehlung");
  SV_Stellgrad_Befeuchtung              = deviceState.getVariableByKey("Stellgrad_Befeuchtung");
  SV_Stellgrad_Entfeuchtung             = deviceState.getVariableByKey("Stellgrad_Entfeuchtung");
  SV_Verdichter_on_                     = deviceState.getVariableByKey("Verdichter_on");
  Startup_                              = deviceState.getVariableByKey("Startup_finished");
  CounterTuer_                          = deviceState.getVariableByKey("Counter_Tuer");

  const_duty_cycle_ ->setValue(1000.0);
  const_freq_->setValue(1000.0);

  auto TempConfig       = dynamic_cast<appengine::deviceConfig::DeviceParameterConfiguration &>(SV_Temperatur_Variable_->configuration());
  auto FeuchteConfig    = dynamic_cast<appengine::deviceConfig::DeviceParameterConfiguration &>(SV_Feuchte_Variable_->configuration());


  auto Sollwert_Temp_Config = TempConfig.setPointConfiguration();
  auto Sollwert_Feuchte_Config = FeuchteConfig.setPointConfiguration();
  SV_Sollwert_Temperatur_ = deviceState.getVariableByKey(Sollwert_Temp_Config->name());
  SV_Sollwert_Feuchte_ = deviceState.getVariableByKey(Sollwert_Feuchte_Config->name());





  
//     std::vector<appengine::asio::SignalConnectionPtr> subscriptions_{};
//   std::shared_ptr<appengine::state::StateVariable> Heizung_Bef_;
//   std::shared_ptr<appengine::state::StateVariable> MV_Kuehlung_;
//   std::shared_ptr<appengine::state::StateVariable> Abschlaemmen_;
//   std::shared_ptr<appengine::state::StateVariable> Entleerpumpe_;
//   std::shared_ptr<appengine::state::StateVariable> Heizung_Kesselrand;
//   std::shared_ptr<appengine::state::StateVariable> Freigabe_Verfluessigerluefter;
//   std::shared_ptr<appengine::state::StateVariable> Heizung_Innenraum;
//   std::shared_ptr<appengine::state::StateVariable> Heizung_Tuer;
//   std::shared_ptr<appengine::state::StateVariable> Uebertemperatur;
//   std::shared_ptr<appengine::state::StateVariable> MV_Entfeuchtung;
//   std::shared_ptr<appengine::state::StateVariable> MV_Druckluft;
//   std::shared_ptr<appengine::state::StateVariable> Ansteuerung_Wassereinlass;
//   std::shared_ptr<appengine::state::StateVariable> Wasserstand_oben_Config_;
//   std::shared_ptr<appengine::state::StateVariable> Wasserstand_oben_Config_;
//   std::shared_ptr<appengine::state::StateVariable> Ansteuerung_Verdichter;
//   std::shared_ptr<appengine::state::StateVariable> Luefter_Innenraum;
//   std::shared_ptr<appengine::state::StateVariable> heatingPower_Freq_;
//   std::vector<appengine::asio::SignalConnectionPtr> subscriptions_{};
//   std::shared_ptr<appengine::state::StateVariable> SV_Sollwert_Temperatur_;
//   std::shared_ptr<appengine::state::StateVariable> SV_Temperatur_Variable_;
//   std::shared_ptr<appengine::state::StateVariable> SV_Sollwert_Feuchte_;
//   std::shared_ptr<appengine::state::StateVariable> SV_Feuchte_Variable_;
//   std::shared_ptr<appengine::state::StateVariable> SV_Tuer_Variable_;

  // tempSetPointVariable_ = deviceState.getVariableByKey("Temperature_Setpoint");

  // TODO: alle bool_inXX/real_inXX und bool_outXX/real_outXX/alarm_XX Variablen hier holen.
//     struct Inputs {
//     // Eingangswerte aus bool_inXX / real_inXX / reset_flag
//     bool reset_flag{};
//     bool Sammelalarm_quittiert{};
//     bool Tuer_offen{};
//     bool Sollwert_Feuchte_aktiv{};
//     bool Steuerkontakt_Standby{};
//     bool Steuerkontakt_Befeuchtung_aus{};
//     bool Steuerkontakt_Entfeuchtung_aus{};
//     bool Entleerbehaelter_Oben{};
//     bool Wasserkanister_leer{};
//     bool Entleerbehaelter_Unten{};
//     bool Sammelalarm{};

//     double Istwert_Temperatur{};
//     double Sollwert_Temperatur{};
//     double Temperaturband{};
//     double Istwert_Ueberwachungsregler{};
//     double Klasse_Ueberwachungsregler{};
//     double Grenzwert_Untertemperatur{};
//     double Istwert_Feuchte{};
//     double Sollwert_Feuchte{};
//     double Feuchteband{};
//     double Sollwert_Luefter{};
//     double Istwert_Temperatur_Tuer{};
//     double Istwert_Temperatur_Verdampferausgang{};
//     double Temperatur_Feuchtemodul{};
//     double Bandalarm_nach{};
//     double Betauungsschutz{};
//     double real_in11{}; // du nutzt real_in11 später direkt in alarm_15
//   };

  //Initialize PT1 Filter

  FILTERED_TEMP.initialize(0.25,1);
  FILTER_TUER.initialize(0.25,1);
  return true;
}

#endif



void Controller::step() {
#ifdef BUILD_TARGET_SOM
  ClimateAlgorithm::Inputs in{};
  in.Istwert_Temperatur  = FILTERED_TEMP.step(SV_Temperatur_Variable_->toType<double>());
  in.Sollwert_Temperatur = SV_Sollwert_Temperatur_ ->toType<double>();
  in.Entleerbehaelter_Oben  = Wasserstand_Oben_Config_->toType<bool>();
  in.Entleerbehaelter_Unten = Wasserstand_Unten_Config_->toType<bool>();
  in.Istwert_Feuchte  = SV_Feuchte_Variable_->toType<double>();
  in.Sollwert_Feuchte = SV_Sollwert_Feuchte_->toType<double>();
  in.Istwert_Temperatur_Tuer = FILTER_TUER.step(SV_Tuer_Variable_->toType<double>());
  in.Betauungsschutz = 50.0;
  in.Grenzwert_Untertemperatur = -80.0;
  in.Feuchteband=10.0;
  in.Istwert_Temperatur_Verdampferausgang = SV_Verdampferausgang_->toType<double>();
  in.Sollwert_Feuchte = SV_Sollwert_Feuchte_->toType<double>();
  in.Istwert_Ueberwachungsregler=in.Istwert_Temperatur;
  in.Klasse_Ueberwachungsregler = 3.0;
  in.reset_flag =false;
  in.Sammelalarm = false;
  in.Sollwert_Feuchte_aktiv = true;
  in.Temperaturband = 5.0;
  in.Temperatur_Feuchtemodul = SV_Befeuchtungsmodul_->toType<double>();
  in.Wasserkanister_leer = false;
  in.Tuer_offen = false;


  // TODO: reset_flag und bool_inXX lesen:
  // in.reset_flag = deviceState.getVariableByKey("reset_flag")->toType<bool>();
  // in.Sammelalarm_quittiert = ... bool_in01
  // ...
  // in.Istwert_Temperatur = real_in01
  // ...

  // Minimal-Beispiel (falls du erstmal nur Temperatur/Setpoint testest):
  //in.Istwert_Temperatur = tempVariable_ ? tempVariable_->toType<double>() : 0.0;
  //in.Sollwert_Temperatur = tempSetPointVariable_ ? tempSetPointVariable_->toType<double>() : 25.0;

  auto out = algo_.step(in);

  Heizung_Bef_Config_ -> setValue(out.bool_out17);
  MV_Kuehlung_Config_ ->setValue(out.bool_out18);
  Abschlaemmen_Config_->setValue(out.bool_out20);
  Entleerpumpe_Config_->setValue(out.bool_out16);
  Heizung_Kesselrand_Config_->setValue(out.bool_out12);
  Freigabe_Verfluessigerluefter_Config_->setValue(out.bool_out13);
  Heizung_Innenraum_Config_->setValue(out.bool_out09);
  Heizung_Tuer_Config_->setValue(out.bool_out11);
  Uebertemperatur_Config_->setValue(true);
  MV_Entfeuchtung_Config_->setValue(out.bool_out19);
  MV_Druckluft_Config_->setValue(false);

  Ansteuerung_Wassereinlass_Config_->setValue(out.bool_out14);
  //Ansteuerung_Verdichter_Config_->setValue(out.real_out21*20.0);
  SV_Verdichter_on_->setValue(1);
  Ansteuerung_Verdichter_Config_->setValue(static_cast<int> (out.real_out21*10.0));
  Verdichter_Duty_Config->setValue(500);

  SV_Stellgrad_Heizung->setValue(out.Stellgrad_Heizung);
  SV_Stellgrad_Kuehlung->setValue(out.Stellgrad_Kuehlung);
  SV_Stellgrad_Befeuchtung ->setValue(out.Stellgrad_Befeuchtung);
  SV_Stellgrad_Entfeuchtung->setValue(out.Stellgrad_Entfeuchtung);
  Startup_->setValue(out.Startup);
  CounterTuer_->setValue(out.Counter_Tuer);

  // TODO: bool_outXX / real_outXX / alarm_XX setzen:
  // deviceState.getVariableByKey("bool_out01")->set(out.bool_out01);
  // deviceState.getVariableByKey("real_out09")->set(out.real_out09);
#endif
}

void Controller::terminate() {
#ifdef BUILD_TARGET_SOM
  subscriptions_.clear();
#endif
}

#ifdef BUILD_TARGET_SOM
ControllerBase *create() {

  return new Controller;
}
#endif
