#include <Arduino.h>
#include <ArduinoLog.h>

#include "Config.h"
#include "Pins.h"
#include "NFC.h"
#include "OTAProxy.h"

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

#include <WiFiClient.h>
#include <PubSubClient.h>
#include <SPI.h>
#include <MFRC522.h>
#include <SSD1306Wire.h>

WiFiClient espClient;
Config_Data config;

PubSubClient* mqtt;
NFC* nfc;
OTAProxy* ota;

void setup_wifi() 
{
    delay(10);
    Serial.println("Connecting Wifi");

    WiFi.mode(WIFI_STA);
    WiFi.begin(config.WLAN_SSID, config.WLAN_Password);

    while (WiFi.status() != WL_CONNECTED)
    {
        delay(500);
    }

    randomSeed(micros());
    Serial.println("WiFi connected");
}

void reconnect() 
{
    while (!mqtt->connected())
    {
        String clientId = "FabReader_";
        clientId += String(config.ID);
        if (mqtt->connect(clientId.c_str()))
        {
            Serial.println("connected");
            char id[6] = "00000";
            sprintf(id, "%05d", config.ID);
            mqtt->publish("fabreader", id);

            char topic[] = "fabreader/00000/#";
            sprintf(topic, "fabreader/%05d/#", config.ID);

            mqtt->subscribe(topic);
        } else {
            Serial.print("failed, rc=");
            Serial.print(mqtt->state());
            Serial.println(" try again in 5 seconds");
            delay(5000);
        }
    }
}

void callback(char* topic, byte* payload, unsigned int length) 
{
    if(ota->hasActiveOTA())
    {
        ota->continueOTA(topic, payload, length);
    }
}

void setup()
{
    config.ID = 1;
    strcpy(config.WLAN_SSID, "");
    strcpy(config.WLAN_Password, "");
    strcpy(config.MQTT_Broker, "");

    Serial.begin(115200);
    Serial.print("\n\n\n");
    Serial.println("Booting ...");
    
    pinMode(PIN_BUZZER,   OUTPUT);
    pinMode(PIN_BUTTON,   INPUT);
    pinMode(PIN_ETH_SPI_SS,   OUTPUT);
    digitalWrite(PIN_ETH_SPI_SS, HIGH);

    Serial.println("NFC ...");
    nfc = new NFC(PIN_RFID_SPI_SS, PIN_RFID_RST);

    setup_wifi();

    mqtt = new PubSubClient(espClient);
    mqtt->setServer(config.MQTT_Broker, config.MQTT_Port);
    mqtt->setCallback(callback);

    ota = new OTAProxy(mqtt, nfc, config.ID);
}

void loop()
{
    if (!mqtt->connected()) 
    {
        reconnect();
    }
    mqtt->loop();

    if(!ota->hasActiveOTA() && nfc->hasNewCard())
    {
        ota->startOTA();
    }
    if(ota->hasActiveOTA() && nfc->isCardLost())
    {
        ota->cancelOTA();
    }
}