
#ifndef _WIFI_FUNCTIONS_H_
#define _WIFI_FUNCTIONS_H_

#include <WiFi.h>
#include <MQTT.h>

#include "wifi_settings.h"
#include "helpfunctions.h"

bool force_ec_measurement=false;


struct mqttValueTiming{
    float minchange;
    float maxchange;
    unsigned long mintime;
    unsigned long maxtime;
    float lastvalue=0;
    unsigned long lasttime=0;
};


WiFiClient net;
MQTTClient client;

bool sendallnext_flag=false;
bool enableTiming=true;



bool publishValueTimed(String topic,float value,uint8_t decimals,mqttValueTiming &mqttvt,unsigned long loopmillis);
void publishValue(String topic,float value,uint8_t decimals);
void publishInfo(String topic,String text);

void connect() {
  Serial.print("checking wifi...");
  uint8_t timeout=0;
  while (WiFi.status() != WL_CONNECTED && timeout<10) {
    timeout++;
    Serial.print(".");
    delay(500);
  }
  
  if (WiFi.status() == WL_CONNECTED)
  {
    Serial.print("\nconnecting...");
    timeout=0;
    #define CONNECT_TIMEOUT 5
    while (!client.connect(client_id, "public", "public") && timeout<CONNECT_TIMEOUT) {
        Serial.print(".");
        delay(1000);
        timeout++;
    }
    if (timeout>=CONNECT_TIMEOUT) {
        Serial.println("\nconnection failed!");
    }else{
        Serial.println("\nconnected!");
        client.subscribe((String)client_id+"/sendall");
        client.subscribe((String)client_id+"/ec/trigger");
        client.subscribe((String)client_id+"/errorack");
        client.subscribe((String)client_id+"/reboot");
    }


  }
}


void messageReceived(String &topic, String &payload) {
  Serial.println("incoming: " + topic + " - " + payload);
  if (topic==((String)client_id+"/sendall") && payload=="true") {
    sendallnext_flag=true;
    Serial.println("Send all values next time");
  }
  if (topic==((String)client_id+"/ec/trigger") && payload=="true") {
    force_ec_measurement=true; 
    Serial.println("Forced EC Measurement");
  }
  if (topic==((String)client_id+"/errorack") && payload=="true") { //error acknowledge
    valueError=false; 
    Serial.println("Reset value error flag");
  }
  if (topic==((String)client_id+"/reboot") && payload=="true") { //error acknowledge
    Serial.println("Reboot by mqtt");
    delay(100);
    ESP.restart();    
  }
}

bool mqtt_loop(unsigned long loopmillis) {
    static unsigned long last_client_loop=0;
    #define CLIENT_LOOP_INTERVAL 10 //ms. fixes some wifi issues. from example https://registry.platformio.org/libraries/256dpi/MQTT/examples/ESP32DevelopmentBoard/ESP32DevelopmentBoard.ino
    if (loopmillis >= last_client_loop+CLIENT_LOOP_INTERVAL) {
        last_client_loop=loopmillis;
        client.loop();

        static unsigned long last_connection_try=0;
        #define RETRY_CONNECTION 60000
        if (!client.connected()) {
            if (loopmillis-last_connection_try>RETRY_CONNECTION) {
                connect();
            }
        }else{
            return true;
        }
    }
    return false;
}

bool publishValueTimedOverride(String topic,float value,uint8_t decimals,mqttValueTiming &mqttvt,unsigned long loopmillis) {
  mqttvt.lasttime=loopmillis;
  mqttvt.lastvalue=value;
  publishValue(topic,value,decimals);
  return true;
}

bool publishValueTimed(String topic,float value,uint8_t decimals,mqttValueTiming &mqttvt,unsigned long loopmillis) {
    unsigned long timediff=loopmillis-mqttvt.lasttime;
    float valuediff=abs(value-mqttvt.lastvalue);
    valuediff=constrain(valuediff,mqttvt.minchange,mqttvt.maxchange);
    unsigned long sendafter=mapf(valuediff,mqttvt.minchange,mqttvt.maxchange,mqttvt.maxtime,mqttvt.mintime); //map valuediff to time when to send
    /*Serial.println();
    Serial.print("timediff="); Serial.print(timediff);
    Serial.print(" valuediff="); Serial.print(valuediff);
    Serial.print(" sendafter="); Serial.println(sendafter);*/
    if (timediff>=sendafter || !enableTiming) {
        mqttvt.lasttime=loopmillis;
        mqttvt.lastvalue=value;
        publishValue(topic,value,decimals);
        return true;
    }
    return false;
}

void publishValue(String topic,float value,uint8_t decimals) {
    char buffer[16];
    dtostrf(value,1,decimals,buffer);
    client.publish((String)client_id+"/"+topic, buffer);
    Serial.print("Publish Topic="); Serial.print((String)client_id+"/"+topic); Serial.print(" Message="); Serial.println(buffer);
}

void publishInfo(String topic,String text) {
    client.publish((String)client_id+"/"+topic, text);
    Serial.print("Publish Topic="); Serial.print((String)client_id+"/"+topic); Serial.print(" Message="); Serial.println(text);
}

#endif