// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright (C) 2022 Helge Erbe and others
 */
#include "VictronMppt.h"
#include "MqttHandleVedirect.h"
#include "MqttSettings.h"
#include "MessageOutput.h"




MqttHandleVedirectClass MqttHandleVedirect;

// #define MQTTHANDLEVEDIRECT_DEBUG

void MqttHandleVedirectClass::init(Scheduler& scheduler)
{
    scheduler.addTask(_loopTask);
    _loopTask.setCallback(std::bind(&MqttHandleVedirectClass::loop, this));
    _loopTask.setIterations(TASK_FOREVER);
    _loopTask.enable();

    // initially force a full publish
    this->forceUpdate();
}

void MqttHandleVedirectClass::forceUpdate()
{
    // initially force a full publish
    _nextPublishUpdatesOnly = 0;
    _nextPublishFull = 1;
}


void MqttHandleVedirectClass::loop()
{
    CONFIG_T& config = Configuration.get();

    if (!MqttSettings.getConnected() || !config.Vedirect.Enabled) {
        return;
    }

    if (!VictronMppt.isDataValid()) {
        return;
    }

    if ((millis() >= _nextPublishFull) || (millis() >= _nextPublishUpdatesOnly)) {
        // determine if this cycle should publish full values or updates only
        if (_nextPublishFull <= _nextPublishUpdatesOnly) {
            _PublishFull = true;
        } else {
            _PublishFull = !config.Vedirect.UpdatesOnly;
        }

        #ifdef MQTTHANDLEVEDIRECT_DEBUG
        MessageOutput.printf("\r\n\r\nMqttHandleVedirectClass::loop millis %lu   _nextPublishUpdatesOnly %u   _nextPublishFull %u\r\n", millis(), _nextPublishUpdatesOnly, _nextPublishFull);
        if (_PublishFull) {
            MessageOutput.println("MqttHandleVedirectClass::loop publish full");
        } else {
            MessageOutput.println("MqttHandleVedirectClass::loop publish updates only");
        }
        #endif

        auto spMpptData = VictronMppt.getData();
        String value;
        String topic = "victron/";
        topic.concat(spMpptData->SER);
        topic.concat("/");

        if (_PublishFull || spMpptData->PID != _kvFrame.PID)
            MqttSettings.publish(topic + "PID", spMpptData->getPidAsString().data());
        if (_PublishFull || strcmp(spMpptData->SER, _kvFrame.SER) != 0)
            MqttSettings.publish(topic + "SER", spMpptData->SER );
        if (_PublishFull || strcmp(spMpptData->FW, _kvFrame.FW) != 0)
            MqttSettings.publish(topic + "FW", spMpptData->FW);
        if (_PublishFull || spMpptData->LOAD != _kvFrame.LOAD)
            MqttSettings.publish(topic + "LOAD", spMpptData->LOAD == true ? "ON": "OFF");
        if (_PublishFull || spMpptData->CS != _kvFrame.CS)
            MqttSettings.publish(topic + "CS", spMpptData->getCsAsString().data());
        if (_PublishFull || spMpptData->ERR != _kvFrame.ERR)
            MqttSettings.publish(topic + "ERR", spMpptData->getErrAsString().data());
        if (_PublishFull || spMpptData->OR != _kvFrame.OR)
            MqttSettings.publish(topic + "OR", spMpptData->getOrAsString().data());
        if (_PublishFull || spMpptData->MPPT != _kvFrame.MPPT)
            MqttSettings.publish(topic + "MPPT", spMpptData->getMpptAsString().data());
        if (_PublishFull || spMpptData->HSDS != _kvFrame.HSDS) {
            value = spMpptData->HSDS;
            MqttSettings.publish(topic + "HSDS", value);
        }
        if (_PublishFull || spMpptData->V != _kvFrame.V) {
            value = spMpptData->V;
            MqttSettings.publish(topic + "V", value);
        }
        if (_PublishFull || spMpptData->I != _kvFrame.I) {
            value = spMpptData->I;
            MqttSettings.publish(topic + "I", value);
        }
        if (_PublishFull || spMpptData->P != _kvFrame.P) {
            value = spMpptData->P;
            MqttSettings.publish(topic + "P", value);
        }
        if (_PublishFull || spMpptData->VPV != _kvFrame.VPV) {
            value = spMpptData->VPV;
            MqttSettings.publish(topic + "VPV", value);
        }
        if (_PublishFull || spMpptData->IPV != _kvFrame.IPV) {
            value = spMpptData->IPV;
            MqttSettings.publish(topic + "IPV", value);
        }
        if (_PublishFull || spMpptData->PPV != _kvFrame.PPV) {
            value = spMpptData->PPV;
            MqttSettings.publish(topic + "PPV", value);
        }
        if (_PublishFull || spMpptData->E != _kvFrame.E) {
            value = spMpptData->E;
            MqttSettings.publish(topic + "E", value);
        }
        if (_PublishFull || spMpptData->H19 != _kvFrame.H19) {
            value = spMpptData->H19;
            MqttSettings.publish(topic + "H19", value);
        }
        if (_PublishFull || spMpptData->H20 != _kvFrame.H20) {
            value = spMpptData->H20;
            MqttSettings.publish(topic + "H20", value);
        }
        if (_PublishFull || spMpptData->H21 != _kvFrame.H21) {
            value = spMpptData->H21;
            MqttSettings.publish(topic + "H21", value);
        }
        if (_PublishFull || spMpptData->H22 != _kvFrame.H22) {
            value = spMpptData->H22;
            MqttSettings.publish(topic + "H22", value);
        }
        if (_PublishFull || spMpptData->H23 != _kvFrame.H23) {
            value = spMpptData->H23;
            MqttSettings.publish(topic + "H23", value);
        }
        if (!_PublishFull) {
            _kvFrame = *spMpptData;
        }

        // now calculate next points of time to publish
        _nextPublishUpdatesOnly = millis() + (config.Mqtt.PublishInterval * 1000);

        if (_PublishFull) {
            // when Home Assistant MQTT-Auto-Discovery is active,
            // and "enable expiration" is active, all values must be published at
            // least once before the announced expiry interval is reached
            if ((config.Vedirect.UpdatesOnly) && (config.Mqtt.Hass.Enabled) && (config.Mqtt.Hass.Expire)) {
                _nextPublishFull = millis() + (((config.Mqtt.PublishInterval * 3) - 1) * 1000);

                #ifdef MQTTHANDLEVEDIRECT_DEBUG
                uint32_t _tmpNextFullSeconds = (config.Mqtt_PublishInterval * 3) - 1;
                MessageOutput.printf("MqttHandleVedirectClass::loop _tmpNextFullSeconds %u - _nextPublishFull %u \r\n", _tmpNextFullSeconds, _nextPublishFull);
                #endif

            } else {
                // no future publish full needed
                _nextPublishFull = UINT32_MAX;
            }
        }

        #ifdef MQTTHANDLEVEDIRECT_DEBUG
        MessageOutput.printf("MqttHandleVedirectClass::loop _nextPublishUpdatesOnly %u   _nextPublishFull %u\r\n", _nextPublishUpdatesOnly, _nextPublishFull);
        #endif
    }
}