#pragma once
#include <iostream>
#include <thread>
#include <chrono>
#include <ctime>
#include <vector>
#include <string>
#include "openweathermap.h"
#include "MqttClient.h"
#include "dbSqlite.h"
#include "structs.h"

#define DEBUG true

using std::string;
using std::cout;
using std::endl;
using std::thread;

// Database object
dbSqlite* db;
openweathermap* owmw;
MqttClient* mqttClient;

// Thread for openweathermap:getWeather
void schedulerWeather(int time) {
    if (DEBUG) cout << "Wetterstation::schedulerWeather()" << endl;
    string topic;
    string weather;
    std::vector<Region> region;
    std::vector<Frontend> frontend;

    while (1) {
        region = db->queryRegions();
        frontend = db->queryFrontends();
        for (int i = 0; i < region.size(); i++) {
            cout << "Weather new RUN(" << region[i].plz <<") ";
            if (DEBUG) cout << "Wetterstation::schedulerWeather(" + region[i].plz + ")" << endl;
            owmw->getWeather(region[i].plz, region[i].lngCode);
            weather = db->getFrontendDataWeather().c_str();
            for (int fr = 0; fr < frontend.size(); fr++) {
                if (frontend[fr].plz == region[i].plz) {
                    cout << "Send weather to frontend: " << frontend[fr].frontendId << endl;
                    topic = db->getSettings().mqtt_topic_frontend + frontend[fr].frontendId + "/weather";
                    mqttClient->send_message(weather.c_str(), topic.c_str());
                    std::this_thread::sleep_for(std::chrono::milliseconds(50));
                }
            }
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(time));
    }
}

// Thread for openweathermap:getForecast
void schedulerForecast(int time) {
    if (DEBUG) cout << "Wetterstation::schedulerForecast()" << endl;
    string topic;
    string forecast;
    std::vector<Region> region;
    std::vector<Frontend> frontend;

    while (1) {
        region = db->queryRegions();
        frontend = db->queryFrontends();
        for (int i = 0; i < region.size(); i++) {
            cout << "Forecast new RUN(" << region[i].plz << ") ";
            if (DEBUG) cout << "Wetterstation::schedulerForecast(" + region[i].plz + ")" << endl;
            owmw->getForecast(region[i].plz, region[i].lngCode);
            forecast = db->getFrontendDataForecast().c_str();
            for (int fr = 0; fr < frontend.size(); fr++) {
                if (frontend[fr].plz == region[i].plz) {
                    cout << "Send forecast to frontend: " << frontend[fr].frontendId << endl;
                    topic = db->getSettings().mqtt_topic_frontend + frontend[fr].frontendId + "/forecast";
                    mqttClient->send_message(forecast.c_str(), topic.c_str());
                    std::this_thread::sleep_for(std::chrono::milliseconds(50));
                }
            }
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(time));
    }
}

// Thread for dbSqlite:getGraphFromInfluxDb
void schedulerInfluxGraph(int time) {
    if (DEBUG) cout << "Wetterstation::schedulerInfluxGraph()" << endl;
    string topic;
    string influxData;
    std::vector<Region> region;
    std::vector<Frontend> frontend;

    while (1) {
        region = db->queryRegions();
        frontend = db->queryFrontends();
        for (int i = 0; i < region.size(); i++) {
            cout << "Graph new RUN(" << region[i].plz << ") " << endl;
            if (DEBUG) cout << "Wetterstation::schedulerInfluxGraph(" + region[i].plz + ")" << endl;
            influxData = db->getGraphFromInfluxDb(region[i].plz);
            for (int fr = 0; fr < frontend.size(); fr++) {
                if (frontend[fr].plz == region[i].plz) {
                    cout << "Send InfluxGraph to frontend: " << frontend[fr].frontendId << endl;
                    topic = db->getSettings().mqtt_topic_frontend + frontend[fr].frontendId + "/graph";
                    mqttClient->send_message(influxData.c_str(), topic.c_str());
                    std::this_thread::sleep_for(std::chrono::milliseconds(50));
                }
            }
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(time));
    }
}

// Thread for dbSqlite:getSensorsFromInfluxDb
void schedulerInfluxSensors(int time) {
    if (DEBUG) cout << "Wetterstation::schedulerInfluxSensors()" << endl;
    string topic;
    std::vector<Frontend> frontend;

    while (1) {
        frontend = db->queryFrontends();
        cout << "Sensors new RUN() " << endl;
        for (int fr = 0; fr < frontend.size(); fr++) {
            if (frontend[fr].node1Id.size() > 0) {
                if (frontend[fr].node1Innen.size() > 0) {
                    string innenData = db->getFrontendDataSensors(frontend[fr].node1Id, frontend[fr].node1Innen);
                    if (DEBUG) cout << "Wetterstation::schedulerInfluxSensors(" + frontend[fr].node1Id + ", " + frontend[fr].node1Innen + ")" << endl;
                    cout << "Send InfluxSensors to frontend: " << frontend[fr].frontendId << endl;
                    topic = db->getSettings().mqtt_topic_frontend + frontend[fr].frontendId + "/sensors";
                    mqttClient->send_message(innenData.c_str(), topic.c_str());
                    std::this_thread::sleep_for(std::chrono::milliseconds(50));
                }
                if (frontend[fr].node1Aussen.size() > 0) {
                    string aussenData = db->getFrontendDataSensors(frontend[fr].node1Id, frontend[fr].node1Aussen);
                    if (DEBUG) cout << "Wetterstation::schedulerInfluxSensors(" + frontend[fr].node1Id + ", " + frontend[fr].node1Aussen + ")" << endl;
                    cout << "Send InfluxSensors to frontend: " << frontend[fr].frontendId << endl;
                    topic = db->getSettings().mqtt_topic_frontend + frontend[fr].frontendId + "/sensors";
                    mqttClient->send_message(aussenData.c_str(), topic.c_str());
                    std::this_thread::sleep_for(std::chrono::milliseconds(50));
                }
            }
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(time));
    }
}

void mqttStart() {
    if (DEBUG) cout << "Wetterstation::mqttStart()" << endl;
    mosqpp::lib_init();
    mqttClient = new MqttClient("Wetterstation", db);
    mosqpp::lib_cleanup();
}

// Main method
int main() {
    if (DEBUG) cout << "Wetterstation::main()" << endl;

    // Sockets aktivieren
    WSADATA wsaData;
    int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed: %d\n", iResult);
        return 1;
    }

    // Initialisieren der Datenbank
    db = new dbSqlite();

    // Initialisieren der Openweathermap
    owmw = new openweathermap(db);

    // MQTT starten
    mqttStart();

    // Thread f�r getWeather starten
    thread thrWeather{ schedulerWeather, 60000 };
    std::this_thread::sleep_for(std::chrono::milliseconds(100));

    // Thread f�r getForecast starten
    thread thrForecast{ schedulerForecast, 60000 };
    std::this_thread::sleep_for(std::chrono::milliseconds(100));

    // Thread f�r getGraphFromInfluxDb starten
    thread thrGraph{ schedulerInfluxGraph, 60000 };
    std::this_thread::sleep_for(std::chrono::milliseconds(100));

    // Thread f�r getSensorsFromInfluxDb starten
    thread thrSensors{ schedulerInfluxSensors, 30000 };
    std::this_thread::sleep_for(std::chrono::milliseconds(100));

    while (1) {
        Sleep(1000);
    }
}