'use strict';

// Handler functions for pumpingStation commands. Each handler receives:
//   source: the domain (specificClass) instance — has the public methods
//           (changeMode, calibratePredicted*, setManualInflow, ...).
//   msg:    the Node-RED input message.
//   ctx:    { node, RED, send, logger } — provided by BaseNodeAdapter.
//
// Handlers are pure functions: they don't keep state. Validation that goes
// beyond the registry's typeof-check ladder lives here.

function _logger(source, ctx) {
  return ctx?.logger || source?.logger || null;
}

exports.setMode = (source, msg) => {
  source.changeMode(msg.payload);
};

exports.registerChild = (source, msg, ctx) => {
  const log = _logger(source, ctx);
  const childId = msg.payload;
  const childObj = ctx?.RED?.nodes?.getNode?.(childId);
  if (!childObj || !childObj.source) {
    log?.warn?.(`registerChild: child '${childId}' not found or has no .source`);
    return;
  }
  source.childRegistrationUtils.registerChild(childObj.source, msg.positionVsParent);
};

exports.calibrateVolume = (source, msg, ctx) => {
  const log = _logger(source, ctx);
  const v = parseFloat(msg.payload);
  if (!Number.isFinite(v)) {
    log?.warn?.(`cmd.calibrate.volume: non-numeric payload '${msg.payload}'`);
    return;
  }
  source.calibratePredictedVolume(v);
};

exports.calibrateLevel = (source, msg, ctx) => {
  const log = _logger(source, ctx);
  const v = parseFloat(msg.payload);
  if (!Number.isFinite(v)) {
    log?.warn?.(`cmd.calibrate.level: non-numeric payload '${msg.payload}'`);
    return;
  }
  source.calibratePredictedLevel(v);
};

// The registry has already normalised any accepted shape (number, numeric
// string, or { value, unit } object) to a number in the descriptor unit
// (m3/h) and tagged msg.unit. Handlers just read the normalised scalar.
exports.setInflow = (source, msg, ctx) => {
  const log = _logger(source, ctx);
  const value = Number(msg.payload);
  if (!Number.isFinite(value)) {
    log?.warn?.(`set.inflow: non-numeric payload '${JSON.stringify(msg.payload)}'`);
    return;
  }
  source.setManualInflow(value, msg.timestamp, msg.unit);
};

exports.setOutflow = (source, msg, ctx) => {
  // Manual q_out — basin-docs dashboard injects a drain rate without wiring a
  // real pump. Same normalised shape as set.inflow.
  const log = _logger(source, ctx);
  const value = Number(msg.payload);
  if (!Number.isFinite(value)) {
    log?.warn?.(`set.outflow: non-numeric payload '${JSON.stringify(msg.payload)}'`);
    return;
  }
  source.setManualOutflow(value, msg.timestamp, msg.unit);
};

exports.setDemand = (source, msg, ctx) => {
  const log = _logger(source, ctx);
  // generalFunctions/commandRegistry's _normaliseUnits has already converted
  // msg.payload to m3/h (the descriptor's units.default — see
  // commands/index.js). Accepts {value, unit} objects upstream; we just read
  // the normalized number here. _manualDemand is stored in m3/h, no further
  // conversion needed.
  const demand = Number(msg?.payload);
  if (!Number.isFinite(demand)) {
    log?.warn?.(`set.demand: invalid Qd value '${JSON.stringify(msg?.payload)}'`);
    return;
  }
  if (source.mode !== 'manual') {
    log?.debug?.(
      `set.demand ignored in '${source.mode}' mode; switch to manual to use the demand slider`
    );
    return;
  }
  // forwardDemandToChildren returns a promise — surface failures via logger.
  Promise.resolve(source.forwardDemandToChildren(demand)).catch((err) => {
    log?.error?.(`set.demand: failed to forward demand: ${err && err.message}`);
  });
};
