//this class will handle the output events for the node red node
class OutputUtils {
  constructor() {
    this.output ={};
    this.output['influxdb'] = {};
    this.output['process'] = {};
  }

  checkForChanges(output, format) {
    const changedFields = {};
    for (const key in output) {
      if (output.hasOwnProperty(key) && output[key] !== this.output[format][key]) {
        let value = output[key];
        // For fields: if the value is an object (and not a Date), stringify it.
        if (value !== null && typeof value === 'object' && !(value instanceof Date)) {
          changedFields[key] = JSON.stringify(value);
        } else {
          changedFields[key] = value;
        }
      }
    }

    // Update the saved output state.
    this.output[format] = { ...this.output[format], ...changedFields };

    return changedFields;
  }

  formatMsg(output, config, format) {
  
    //define emtpy message
      let msg = {};

      // Compare output with last output and only include changed values
      const changedFields = this.checkForChanges(output,format);

      if (Object.keys(changedFields).length > 0) {

        switch (format) {
          case 'influxdb':  
            // Extract the relevant config properties.
            const relevantConfig = this.extractRelevantConfig(config);
            // Flatten the tags so that no nested objects are passed on.
            const flatTags = this.flattenTags(relevantConfig);
            msg = this.influxDBFormat(changedFields, config, flatTags);
            
            break;

          case 'process':

            // Compare output with last output and only include changed values
            msg = this.processFormat(changedFields,config);
            //console.log(msg);
            break;

          default:
            console.log('Unknown format in output utils');
            break;
        }
        return msg;
      }
  }
  

  influxDBFormat(changedFields, config , flatTags) {
    // Create the measurement and topic using softwareType and name config.functionality.softwareType + .
    const measurement = `${config.functionality?.softwareType}_${config.general?.id}`;
    const payload = {
      measurement: measurement,
      fields: changedFields,
      tags: flatTags,
      timestamp: new Date(),
    };

    const topic = measurement;
    const msg = { topic: topic, payload: payload };
    return msg;
  }

  flattenTags(obj) {
    const result = {};
    for (const key in obj) {
      if (obj.hasOwnProperty(key)) {
        const value = obj[key];
        if (value !== null && typeof value === 'object' && !(value instanceof Date)) {
          // Recursively flatten the nested object.
          const flatChild = this.flattenTags(value);
          for (const childKey in flatChild) {
            if (flatChild.hasOwnProperty(childKey)) {
              result[`${key}_${childKey}`] = String(flatChild[childKey]);
            }
          }
        } else {
          // InfluxDB tags must be strings.
          result[key] = String(value);
        }
      }
    }
    return result;
  }

  extractRelevantConfig(config) {
    
    return {
      // general properties
      id: config.general?.id,
      // functionality properties
      softwareType: config.functionality?.softwareType,
      role: config.functionality?.role,
      // asset properties (exclude machineCurve)
      uuid: config.asset?.uuid,
      tagcode: config.asset?.tagcode,
      geoLocation: config.asset?.geoLocation,
      category: config.asset?.category,
      type: config.asset?.type,
      model: config.asset?.model,
      unit: config.general?.unit,
    };
  }

  processFormat(changedFields,config) {
        // Create the measurement and topic using softwareType and name config.functionality.softwareType + .
        const measurement = `${config.functionality?.softwareType}_${config.general?.id}`;
        const payload = changedFields;
        const topic = measurement;
        const msg = { topic: topic, payload: payload };
        return msg;
  }
}

module.exports = OutputUtils;
