/****************************************************************************
 * This file is part of the project AqHome.
 * AqHome (c) by 2025 Martin Preuss, all rights reserved.
 *
 * The license for this file can be found in the file COPYING which you
 * should have received along with this file.
 ****************************************************************************/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include "./s_setdata.h"
#include "./server_p.h"
#include "aqhome/data/value.h"
#include "aqhome/msg/ipc/data/m_ipcd_setdata.h"
#include "aqhome/msg/mqtt/m_mqtt_publish.h"
#include "aqhome/ipc2/endpoint.h"

#include <gwenhywfar/debug.h>


#define DEBUG_DRY_RUN 0 /* don't actually set value if "1" */



/* ------------------------------------------------------------------------------------------------
 * forward declarations
 * ------------------------------------------------------------------------------------------------
 */

static void _sendDataForDevice(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device,
                               const char *valueName, double valueData);
static void _sendValueToMqtt(AQH_MQTTLOG_SERVER *xo,
                             const AQHMQTT_DEVICE *device,
                             const AQHMQTT_TOPIC *topic,
                             const AQHMQTT_VALUE *value,
                             double valueData);
static const char *_valueTranslatedForDriver(const AQHMQTT_VALUE *value, double valueData);
static GWEN_BUFFER *_createBufferForTopic(const char *deviceId, const AQHMQTT_TOPIC *topic);



/* ------------------------------------------------------------------------------------------------
 * implementations
 * ------------------------------------------------------------------------------------------------
 */

void AQH_MqttLogServer_HandleSetData(AQH_OBJECT *o,
                                     const AQH_MESSAGE *msg,
                                     const GWEN_TAG16_LIST *tagList)
{
  if (o && msg) {
    AQH_MQTTLOG_SERVER *xo;

    xo=AQH_MqttLogServer_GetServerData(o);
    if (xo) {
      AQH_VALUE *recvdValue;
    
      DBG_ERROR(NULL, "Received SETDATA request");
      recvdValue=AQH_IpcdMessageSetData_ReadValue(tagList);
      if (recvdValue) {
        const char *valueName;
        const char *deviceName;
    
        valueName=recvdValue?AQH_Value_GetName(recvdValue):NULL;
        deviceName=recvdValue?AQH_Value_GetDeviceName(recvdValue):NULL;
        if (valueName && deviceName) {
          AQHMQTT_DEVICE *device;
    
          device=AQH_MqttLogServer_FindRegisteredDevice(o, deviceName);
          if (device) {
            double valueData;
    
            DBG_ERROR(NULL, "Sending data to value \"%s\" of device \"%s\"", valueName, deviceName);
            valueData=AQH_IpcdMessageSetData_ReadData(tagList);
            _sendDataForDevice(xo, device, valueName, valueData);
          }
          else {
            DBG_ERROR(NULL, "Device \"%s\" not found", deviceName);
            AQH_MqttLogServer_DumpRegisteredDevices(o);
          }
        }
        else {
          DBG_ERROR(NULL, "Either value name or device name missing in request");
        }
        AQH_Value_free(recvdValue);
      }
      else {
        DBG_ERROR(NULL, "Request does not contain a value object");
      }
    }
  }
}



void _sendDataForDevice(AQH_MQTTLOG_SERVER *xo,
                        const AQHMQTT_DEVICE *device,
                        const char *valueName, double valueData)
{
  const char *deviceId;

  deviceId=AQHMQTT_Device_GetId(device);
  if (deviceId && *deviceId) {
    AQHMQTT_TOPIC_LIST *topicList;

    topicList=AQHMQTT_Device_GetTopicList(device);
    if (topicList) {
      AQHMQTT_TOPIC *topic;

      topic=AQHMQTT_Topic_List_First(topicList);
      while(topic) {
        if (AQHMQTT_Topic_GetDirection(topic)==AQHMQTT_TopicDir_Out) {
          AQHMQTT_VALUE_LIST *valueList;
          AQHMQTT_VALUE *value;

          valueList=AQHMQTT_Topic_GetValueList(topic);
          value=valueList?AQHMQTT_Value_List_GetByName(valueList, valueName):NULL;
          if (value) {
            /* found value, create publish msg, send */
            DBG_ERROR(NULL, "Topic \"%s\" contains value \"%s\"", AQHMQTT_Topic_GetName(topic), valueName);
            _sendValueToMqtt(xo, device, topic, value, valueData);
          }
        } /* if out */
        topic=AQHMQTT_Topic_List_Next(topic);
      } /* while topic */
    }
  }
  else {
    DBG_ERROR(NULL, "Device has no id");
  }
}



void _sendValueToMqtt(AQH_MQTTLOG_SERVER *xo,
                      const AQHMQTT_DEVICE *device,
                      const AQHMQTT_TOPIC *topic,
                      const AQHMQTT_VALUE *value,
                      double valueData)
{
  const char *deviceId;
  const char *translatedValue;
  GWEN_BUFFER *buf;
#if !DEBUG_DRY_RUN
  AQH_MESSAGE *msgOut;
#endif

  deviceId=AQHMQTT_Device_GetId(device);
  buf=_createBufferForTopic(deviceId, topic);
  translatedValue=_valueTranslatedForDriver(value, valueData);
  if (translatedValue && *translatedValue) {
    DBG_ERROR(NULL, "MQTT PUBLISH: %s = %s", GWEN_Buffer_GetStart(buf), translatedValue);
    msgOut=AQH_MqttMessagePublish_new(0, 0, GWEN_Buffer_GetStart(buf), (const uint8_t*)translatedValue, strlen(translatedValue));
  }
  else {
    GWEN_BUFFER *vbuf;

    vbuf=GWEN_Buffer_new(0, 64, 0, 1);
    GWEN_Buffer_AppendArgs(vbuf, "%f", valueData);
    DBG_ERROR(NULL, "MQTT PUBLISH: %s = %s", GWEN_Buffer_GetStart(buf), GWEN_Buffer_GetStart(vbuf));
    msgOut=AQH_MqttMessagePublish_new(0, 0,
                                      GWEN_Buffer_GetStart(buf),
                                      (const uint8_t*)GWEN_Buffer_GetStart(vbuf),
                                      GWEN_Buffer_GetUsedBytes(vbuf));
    GWEN_Buffer_free(vbuf);
  }

#if !DEBUG_DRY_RUN
  if (msgOut)
    AQH_Endpoint_AddMsgOut(xo->mqttEndpoint, msgOut);
  else {
    DBG_ERROR(NULL, "Error creating message");
  }
#endif
  GWEN_Buffer_free(buf);
}



const char *_valueTranslatedForDriver(const AQHMQTT_VALUE *value, double valueData)
{
  const AQHMQTT_TRANSLATION_LIST *translationList;

  translationList=AQHMQTT_Value_GetTranslationList(value);
  if (translationList) {
    const AQHMQTT_TRANSLATION *t;
    int valueAsInt;

    valueAsInt=(int) valueData;
    t=AQHMQTT_Translation_List_GetByAqhValue(translationList, valueAsInt);
    if (t) {
      const char *s;

      s=AQHMQTT_Translation_GetDriverValue(t);
      DBG_ERROR(NULL, "Translated value %d to %s", valueAsInt, s);
      return s;
    }
    else {
      DBG_ERROR(NULL, "No translation found for %d", valueAsInt);
    }
  }
  else {
    DBG_ERROR(NULL, "No translation list");
  }

  return NULL;
}



GWEN_BUFFER *_createBufferForTopic(const char *deviceId, const AQHMQTT_TOPIC *topic)
{
  GWEN_BUFFER *buf;
  const char *s;

  buf=GWEN_Buffer_new(0, 256, 0, 1);
  s=AQHMQTT_Topic_GetBeforeId(topic);
  if (s && *s)
    GWEN_Buffer_AppendString(buf, s);
  GWEN_Buffer_AppendString(buf, deviceId);
  s=AQHMQTT_Topic_GetAfterId(topic);
  if (s && *s)
    GWEN_Buffer_AppendString(buf, s);
  return buf;
}






