#include "config.h"
#include "states.h"
#include "power.h"
#include "gps.h"
#include "lora.h"
#include "button.h"
#include <CayenneLPP.h>

int state;
RTC_DATA_ATTR int bootCount = 0;
CayenneLPP payload(55);

void createPayload()
{
    payload.reset();
    TinyGPSPlus gps = getGps();
    payload.addGPS(1, gps.location.lat(), gps.location.lng(), gps.altitude.meters());
    payload.addAnalogInput(2, powerGetBattVoltage() / 1000);
}

void printPayload() {
    DynamicJsonDocument jsonBuffer(1024);
    JsonObject json = jsonBuffer.to<JsonObject>();
    payload.decodeTTN(payload.getBuffer(), payload.getSize(), json);
    Serial.println("\n########## Payload ##########");
    serializeJsonPretty(json, Serial);
    Serial.println("\n#########################\n");
}

static void bootInfo()
{
    ++bootCount;
    Serial.printf("Boot number: %d\n", bootCount);

    esp_sleep_wakeup_cause_t wakeup_reason;
    wakeup_reason = esp_sleep_get_wakeup_cause();

    switch (wakeup_reason)
    {
    case ESP_SLEEP_WAKEUP_EXT0:
        Serial.println("Wakeup caused by external signal using RTC_IO");
        break;
    case ESP_SLEEP_WAKEUP_EXT1:
        Serial.println("Wakeup caused by external signal using RTC_CNTL");
        break;
    case ESP_SLEEP_WAKEUP_TIMER:
        Serial.println("Wakeup caused by timer");
        break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD:
        Serial.println("Wakeup caused by touchpad");
        break;
    case ESP_SLEEP_WAKEUP_ULP:
        Serial.println("Wakeup caused by ULP program");
        break;
    default:
        Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason);
        break;
    }
}

void setup()
{
    Serial.begin(115200);
    Wire.begin(21, 22);
    bootInfo();
    powerSetup();
    gpsSetup();
    loraSetup();
    buttonSetup();
    state = STATE_INIT;
}

void loop()
{
    loraLoop();
    buttonLoop();

    switch (state)
    {
    case STATE_INIT:
        gpsCheck();
        break;
    case STATE_READY:
        createPayload();
        state = loraSend(payload); // success: STATE_SENDING, error: STATE_READY
        printPayload();
        break;
    case STATE_SENDING:
        // idle
        break;
    case STATE_DONE:
        powerSleep();
        break;
    default:
        break;
    }
}