#include "airtime.h"
#include <Arduino.h>

#define periodsToLog 48

AirTime *airTime;

uint32_t secondsPerPeriod = 3600;
uint32_t lastMillis = 0;
uint32_t secSinceBoot = 0;

// AirTime at;

// Don't read out of this directly. Use the helper functions.
struct airtimeStruct {
    uint32_t periodTX[periodsToLog];     // AirTime transmitted
    uint32_t periodRX[periodsToLog];     // AirTime received and repeated (Only valid mesh packets)
    uint32_t periodRX_ALL[periodsToLog]; // AirTime received regardless of valid mesh packet. Could include noise.
    uint8_t lastPeriodIndex;
} airtimes;

void AirTime::logAirtime(reportTypes reportType, uint32_t airtime_ms)
{
    if (reportType == TX_LOG) {
        DEBUG_MSG("AirTime - Packet transmitted : %ums\n", airtime_ms);
        airtimes.periodTX[0] = airtimes.periodTX[0] + airtime_ms;
    } else if (reportType == RX_LOG) {
        DEBUG_MSG("AirTime - Packet received : %ums\n", airtime_ms);
        airtimes.periodRX[0] = airtimes.periodRX[0] + airtime_ms;
    } else if (reportType == RX_ALL_LOG) {
        DEBUG_MSG("AirTime - Packet received (noise?) : %ums\n", airtime_ms);
        airtimes.periodRX_ALL[0] = airtimes.periodRX_ALL[0] + airtime_ms;
    } else {
        DEBUG_MSG("AirTime - Unknown report time. This should never happen!!\n");
    }
}

uint8_t currentPeriodIndex()
{
    return ((getSecondsSinceBoot() / secondsPerPeriod) % periodsToLog);
}

void airtimeRotatePeriod()
{

    if (airtimes.lastPeriodIndex != currentPeriodIndex()) {
        DEBUG_MSG("Rotating airtimes to a new period = %u\n", currentPeriodIndex());

        for (int i = periodsToLog - 2; i >= 0; --i) {
            airtimes.periodTX[i + 1] = airtimes.periodTX[i];
            airtimes.periodRX[i + 1] = airtimes.periodRX[i];
            airtimes.periodRX_ALL[i + 1] = airtimes.periodRX_ALL[i];
        }
        airtimes.periodTX[0] = 0;
        airtimes.periodRX[0] = 0;
        airtimes.periodRX_ALL[0] = 0;

        airtimes.lastPeriodIndex = currentPeriodIndex();
    }
}

uint32_t *airtimeReport(reportTypes reportType)
{

    if (reportType == TX_LOG) {
        return airtimes.periodTX;
    } else if (reportType == RX_LOG) {
        return airtimes.periodRX;
    } else if (reportType == RX_ALL_LOG) {
        return airtimes.periodRX_ALL;
    }
    return 0;
}

uint8_t getPeriodsToLog()
{
    return periodsToLog;
}

uint32_t getSecondsPerPeriod()
{
    return secondsPerPeriod;
}

uint32_t getSecondsSinceBoot()
{
    return secSinceBoot;
}

AirTime::AirTime() : concurrency::OSThread("AirTime") {}

int32_t AirTime::runOnce()
{
    //DEBUG_MSG("AirTime::runOnce()\n");

    airtimeRotatePeriod();
    secSinceBoot++;

    /*
        This actually doesn't need to be run once per second but we currently use it for the
        secSinceBoot counter.

        If we have a better counter of how long the device has been online (and not millis())
        then we can change this to something less frequent. Maybe once ever 5 seconds?
    */
    return (1000 * 1);
}