// MeasurementRouter — dispatches incoming measurement updates by type and
// derives downstream measurements (volume from level, predicted level from
// pressure). Pure domain over a context bag; no Node-RED dependency.

const { coolprop, interpolation } = require('generalFunctions');

const G = 9.80665;
const ASSUMED_TEMPERATURE_C = 15;
const ATMOSPHERIC_PRESSURE_PA = 101325;

class MeasurementRouter {
  constructor(ctx = {}) {
    if (!ctx.measurements) throw new Error('MeasurementRouter: ctx.measurements is required');
    if (!ctx.basin) throw new Error('MeasurementRouter: ctx.basin is required');

    this.measurements = ctx.measurements;
    this.basin = ctx.basin;
    this.logger = ctx.logger || null;
    this._interp = ctx.interpolation || new interpolation();
  }

  route(measurementType, value, position, eventData = {}) {
    switch (measurementType) {
      case 'level':
        this.onLevelMeasurement(position, value, eventData);
        return true;
      case 'pressure':
        this.onPressureMeasurement(position, value, eventData);
        return true;
      default:
        return false;
    }
  }

  onLevelMeasurement(position, value, context = {}) {
    this.measurements.type('level').variant('measured').position(position)
      .value(value, context.timestamp, context.unit);

    const series = this.measurements.type('level').variant('measured').position(position);
    const levelMeters = series.getCurrentValue('m');
    if (levelMeters == null) return;

    const surfaceArea = this.basin.surfaceArea;
    const volume = surfaceArea > 0 ? Math.max(levelMeters, 0) * surfaceArea : 0;
    const percent = this._interp.interpolate_lin_single_point(
      volume, this.basin.minVol, this.basin.maxVolAtOverflow, 0, 100
    );

    this.measurements.type('volume').variant('measured').position('atequipment')
      .value(volume, context.timestamp, 'm3');
    this.measurements.type('volumePercent').variant('measured').position('atequipment')
      .value(percent, context.timestamp, '%');
  }

  onPressureMeasurement(position, value, context = {}) {
    let kelvin = this.measurements
      .type('temperature').variant('measured').position('atequipment')
      .getCurrentValue('K') ?? null;

    if (kelvin === null) {
      if (this.logger) {
        this.logger.warn('No temperature measurement; assuming 15C for pressure to level conversion.');
      }
      this.measurements.type('temperature').variant('assumed').position('atequipment')
        .value(ASSUMED_TEMPERATURE_C, Date.now(), 'C');
      kelvin = this.measurements.type('temperature').variant('assumed').position('atequipment')
        .getCurrentValue('K');
    }
    if (kelvin == null) return;

    const density = coolprop.PropsSI('D', 'T', kelvin, 'P', ATMOSPHERIC_PRESSURE_PA, 'Water');
    const pressurePa = this.measurements.type('pressure').variant('measured').position(position)
      .getCurrentValue('Pa');
    if (!Number.isFinite(pressurePa) || !Number.isFinite(density)) return;

    const level = pressurePa / (density * G);
    this.measurements.type('level').variant('predicted').position(position)
      .value(level, context.timestamp, 'm');
  }
}

module.exports = MeasurementRouter;
