const { sendToQueue, subscribeToSettingsChange } = require('./../../data/queue');
const { machineIdSync } = require('node-machine-id');
let mashineId = machineIdSync({ original: true });

String.Format = function (b) {
  var a = arguments;
  return b.replace(/(\{\{\d\}\}|\{\d\})/g, function (b) {
    if (b.substring(0, 2) == '{{') return b;
    var c = parseInt(b.match(/\d/)[0]);
    return a[c + 1];
  });
};

let settings = {
  1056: [
    {
      name: 'rpm',
      topic: 'car/{0}/{1}/rpm',
      rate: 1,
      canId: 1056,
      offset: 0,
      bytesToUse: 2,
      min: 0,
      max: 8500,
      precision: 0,
      units: 'rpm',
      rawFormula: { multiplier: 1.0, divider: 1.0, add: 0 },
      formula: '{0}*256+{1}',
    },
    {
      name: 'speed',
      topic: 'car/{0}/{1}/speed',
      rate: 1,
      canId: 1056,
      offset: 2,
      bytesToUse: 2,
      min: 0,
      max: 250,
      precision: 0,
      units: 'km/h',
      rawFormula: { multiplier: 1.0, divider: 1.0, add: 0 },
      formula: '{0}*256+{1}',
    },
    {
      name: 'gear',
      topic: 'car/{0}/{1}/gear',
      rate: 1,
      canId: 1056,
      offset: 4,
      bytesToUse: 2,
      min: 0,
      max: 6,
      precision: 0,
      units: '',
      rawFormula: { multiplier: 1.0, divider: 1.0, add: 0 },
      formula: '{0}',
    },
    {
      name: 'watertemp',
      topic: 'car/{0}/{1}/watertemp',
      rate: 1,
      canId: 1056,
      offset: 6,
      bytesToUse: 2,
      min: 0,
      max: 280,
      precision: 0,
      units: 'C',
      rawFormula: { multiplier: 1.0, divider: 1.0, add: 0 },
      formula: '{0}',
    },
  ],
  1057: [
    {
      name: 'headtemp',
      topic: 'car/{0}/{1}/headtemp',
      rate: 1,
      canId: 1057,
      offset: 0,
      bytesToUse: 2,
      min: 0,
      max: 280,
      precision: 0,
      units: 'C',
      rawFormula: { multiplier: 1.0, divider: 1.0, add: 0 },
      formula: '{0}+{1}',
    },
    {
      name: 'exhausttemp',
      topic: 'car/{0}/{1}/exhausttemp',
      rate: 1,
      canId: 1057,
      offset: 2,
      bytesToUse: 2,
      min: 0,
      max: 2000,
      precision: 0,
      units: 'C',
      rawFormula: { multiplier: 1.0, divider: 1.0, add: 0 },
      formula: '{0}+{1}',
    },
    {
      name: 'oiltemp',
      topic: 'car/{0}/{1}/oiltemp',
      rate: 1,
      canId: 1057,
      offset: 4,
      bytesToUse: 2,
      min: 0,
      max: 300,
      precision: 0,
      units: 'C',
      rawFormula: { multiplier: 1.0, divider: 1.0, add: 0 },
      formula: '{0}+{1}',
    },
    {
      name: 'oilpresure',
      topic: 'car/{0}/{1}/oilpress',
      rate: 1,
      canId: 1057,
      offset: 6,
      bytesToUse: 2,
      min: 0,
      max: 150,
      precision: 0,
      units: 'BAR',
      rawFormula: { multiplier: 1.0, divider: 1.0, add: 0 },
      formula: '{0}+{1}',
    },
  ],
  1058: [
    {
      name: 'brakepresure',
      topic: 'car/{0}/{1}/brakepress',
      rate: 1,
      canId: 1058,
      offset: 0,
      bytesToUse: 2,
      min: 0,
      max: 2000,
      precision: 0,
      units: 'BAR',
      rawFormula: { multiplier: 1.0, divider: 1.0, add: 0 },
      formula: '{0}+{1}',
    },
    {
      name: 'throttleposition',
      topic: 'car/{0}/{1}/throttlepos',
      rate: 1,
      canId: 1058,
      offset: 2,
      bytesToUse: 2,
      min: 0,
      max: 100,
      precision: 0,
      units: '%',
      rawFormula: { multiplier: 1.0, divider: 1.0, add: 0 },
      formula: '{0}+{1}',
    },
    {
      name: 'brakeposition',
      topic: 'car/{0}/{1}/brakepos',
      rate: 1,
      canId: 1058,
      offset: 4,
      bytesToUse: 2,
      min: 0,
      max: 100,
      precision: 0,
      units: '%',
      rawFormula: { multiplier: 1.0, divider: 1.0, add: 0 },
      formula: '{0}+{1}',
    },
    {
      name: 'clutchposition',
      topic: 'car/{0}/{1}/clutchpos',
      rate: 1,
      canId: 1058,
      offset: 6,
      bytesToUse: 2,
      min: 0,
      max: 100,
      precision: 0,
      units: '%',
      rawFormula: { multiplier: 1.0, divider: 1.0, add: 0 },
      formula: '{0}+{1}',
    },
  ],
  1059: [
    {
      name: 'stearingposition',
      topic: 'car/{0}/{1}/steeringpos',
      rate: 1,
      canId: 1059,
      offset: 0,
      bytesToUse: 2,
      min: 0,
      max: 100,
      precision: 0,
      units: '%',
      rawFormula: { multiplier: 1.0, divider: 1.0, add: 0 },
      formula: '{0}+{1}',
    },
    {
      name: 'lambda',
      topic: 'car/{0}/{1}/lambda',
      rate: 1,
      canId: 1059,
      offset: 2,
      bytesToUse: 2,
      min: 0,
      max: 20,
      precision: 2,
      units: 'ratio',
      rawFormula: { multiplier: 1.0, divider: 1.0, add: 0 },
      formula: '{0}+{1}',
    },
  ],
  1060: [
    {
      name: 'fuellevel',
      topic: 'car/{0}/{1}/fuellvl',
      rate: 1,
      canId: 1060,
      offset: 0,
      bytesToUse: 2,
      min: 0,
      max: 100,
      precision: 0,
      units: '%',
      rawFormula: { multiplier: 1.0, divider: 1.0, add: 0 },
      formula: '{0}+{1}',
    },
    {
      name: 'batteryvoltage',
      topic: 'car/{0}/{1}/batteryvoltage',
      rate: 1,
      canId: 1060,
      offset: 2,
      bytesToUse: 2,
      min: 0,
      max: 18,
      precision: 2,
      units: 'V',
      rawFormula: { multiplier: 1.0, divider: 1.0, add: 0 },
      formula: '{0}+{1}',
    },
  ],
};

subscribeToSettingsChange((newSettings) => {
  settings = newSettings;
});

const parse = (hexString, pushToQueue) => {
  const replyList = handleCanFrame(hexString);
  if (pushToQueue) {
    replyList.forEach((reply) => {
      sendToQueue(String.Format(reply.topic, mashineId, '1'), reply.value.toString());
    });
  }

  return replyList;
};

const handleCanFrame = (hexString) => {
  const replyList = [];
  let valueArray; //New object
  valueArray = [];
  valueArray = hexString.split('|');
  const pid = valueArray[1];
  if (typeof settings[pid] !== 'undefined') {
    let data = valueArray.slice(4, valueArray.length);

    settings[pid].forEach((setting) => {
      const reply = {
        value: undefined,
        name: undefined,
        mode: undefined,
        pid: pid,
        min: undefined,
        max: undefined,
        unit: undefined,
        topic: undefined,
      };

      let byteA = data[setting.offset];
      let parsedA = parseInt(byteA, 16);
      let byteB = data[setting.offset + 1];
      let parsedB = parseInt(byteB, 16);
      let calculatedValue = 0;

      //console.log(parsedA, parsedB, setting.name);

      if (parsedA !== 0) {
        const calculationToEvan = String.Format(setting.formula, parsedA, parsedB);
        calculatedValue = eval(calculationToEvan);
        if (calculatedValue === 0) calculatedValue = setting.formula.add;
        else
          calculatedValue =
            (calculatedValue * setting.rawFormula.multiplier) / setting.rawFormula.divider +
            setting.rawFormula.add;

        calculatedValue = !Number.isInteger(calculatedValue)
          ? parseFloat(calculatedValue).toPrecision(setting.precision + 1)
          : calculatedValue;
      }

      reply.value = calculatedValue;
      reply.name = setting.name;
      reply.min = setting.min;
      reply.max = setting.max;
      reply.unit = setting.units;
      reply.topic = setting.topic;

      replyList.push(reply);
    });
  }

  return replyList;
};

module.exports = { parse, handleCanFrame };
