#include "Communicator.h"

Communicator::Communicator(WiFiClient& network, CALLBACK_SIGNATURE) {
  this->_net = network;
  this->mqttCallback = mqttCallback;
  this->_mqtt_client.setBufferSize(1536);
}

Communicator::Communicator(WiFiClient& network) {
  this->_net = network;
  this->_mqtt_client.setBufferSize(1536);
}

void Communicator::connectCallback(CALLBACK_SIGNATURE) {
  this->mqttCallback = mqttCallback;
}
  
void Communicator::loop() {
  _mqtt_client.loop();
}

bool Communicator::ConnectMQTT(const String &server, const String &name, const String &user, const String &password) {
  _mqtt_client.setClient(_net);
  _mqtt_client.setServer(server.c_str(), 1883);
  _mqtt_client.setCallback(mqttCallback);

  byte i = 0;

  if (_mqtt_client.connected()) return true;

  while (!_mqtt_client.connected() && (i < 3)) {
    Serial.println("Attempt MQTT Connection.");
    boolean ret;
    ret = _mqtt_client.connect(name.c_str(), user.c_str(), password.c_str());
    if (ret) {
      Serial.println("Connected to MQTT");
      return true;

    } else {
      int Status = _mqtt_client.state();

      switch (Status)
      {
        case -4:
          Serial.println(F("Connection timeout"));
          break;

        case -3:
          Serial.println(F("Connection lost"));
          break;

        case -2:
          Serial.println(F("Connect failed"));
          break;

        case -1:
          Serial.println(F("Disconnected"));
          break;

        case 1:
          Serial.println(F("Bad protocol"));
          break;

        case 2:
          Serial.println(F("Bad client ID"));
          break;

        case 3:
          Serial.println(F("Unavailable"));
          break;

        case 4:
          Serial.println(F("Bad credentials"));
          break;

        case 5:
          Serial.println(F("Unauthorized"));
          break;
      }

    }

    Serial.print(".");
    i++;
    delay(5000);
  }

  return false;

}

void Communicator::Subscribe(const char* topic) {
  Serial.println("Subscribe to: " + String(topic));
  _mqtt_client.subscribe(topic);
}

void Communicator::mqtt_discovery(const String topic, StaticJsonDocument<1536> &entity) {
  String payload;
  serializeJson(entity, payload);

  bool response = ConnectMQTT(MQTT_BROKER.toString(), MQTT_NAME, MQTT_USER, MQTT_PASSWORD);
  if (response)
  {
    Serial.print("Sending discovery payload to ");
    Serial.println(topic);
    Serial.println(payload);

    _mqtt_client.publish(topic.c_str(), payload.c_str(), false);

    const char* mode = entity["mode_cmd_t"];
    if (mode) {
      Subscribe(mode);
    }
    const char* temp = entity["temp_cmd_t"];
    if (temp) {
      Subscribe(temp);
    }
    const char* temp_hi = entity["temp_hi_cmd_t"];
    if (temp_hi) {
      Subscribe(temp_hi);
    }
    const char* temp_lo = entity["temp_lo_cmd_t"];
    if (temp_lo) {
      Subscribe(temp_lo);
    }

    _mqtt_client.loop();
  }
}
    
void Communicator::publish_data(String topic, String value) {
  _mqtt_client.publish(topic.c_str(), value.c_str(), true);
}
