// Basin geometry for a wet-well pumping station.
//
// Models the basin as a rectangular prism (constant cross-section), so
// volume = level × surfaceArea. Owns the level↔volume conversions and the
// derived threshold volumes used by control + safety. Pure domain — no
// Node-RED, no logger, no side effects beyond construction.

class BasinGeometry {
  /**
   * @param {object} basinConfig - { volume, height, inflowLevel, outflowLevel, overflowLevel }
   * @param {object} hydraulicsConfig - { minHeightBasedOn: 'inlet' | 'outlet' }
   */
  constructor(basinConfig, hydraulicsConfig) {
    const volEmptyBasin = basinConfig.volume;
    const heightBasin = basinConfig.height;
    const inflowLevel = basinConfig.inflowLevel;
    const outflowLevel = basinConfig.outflowLevel;
    const overflowLevel = basinConfig.overflowLevel;
    const inletPipeDiameter = basinConfig.inletPipeDiameter;
    const outletPipeDiameter = basinConfig.outletPipeDiameter;
    const minHeightBasedOn = hydraulicsConfig?.minHeightBasedOn;

    const surfaceArea = volEmptyBasin / heightBasin;

    // maxVol ≡ volEmptyBasin under the constant cross-section assumption;
    // kept as a separate field for naming symmetry with the trigger volumes.
    const maxVol = heightBasin * surfaceArea;
    const maxVolAtOverflow = overflowLevel * surfaceArea;
    const minVolAtOutflow = outflowLevel * surfaceArea;
    const minVolAtInflow = inflowLevel * surfaceArea;
    const minVol = minHeightBasedOn === 'inlet' ? minVolAtInflow : minVolAtOutflow;

    this._volEmptyBasin = volEmptyBasin;
    this._heightBasin = heightBasin;
    this._inflowLevel = inflowLevel;
    this._outflowLevel = outflowLevel;
    this._overflowLevel = overflowLevel;
    this._inletPipeDiameter = inletPipeDiameter;
    this._outletPipeDiameter = outletPipeDiameter;
    this._surfaceArea = surfaceArea;
    this._maxVol = maxVol;
    this._maxVolAtOverflow = maxVolAtOverflow;
    this._minVolAtInflow = minVolAtInflow;
    this._minVolAtOutflow = minVolAtOutflow;
    this._minVol = minVol;
    this._minHeightBasedOn = minHeightBasedOn;
  }

  get volEmptyBasin()    { return this._volEmptyBasin; }
  get heightBasin()      { return this._heightBasin; }
  get inflowLevel()      { return this._inflowLevel; }
  get outflowLevel()     { return this._outflowLevel; }
  get overflowLevel()    { return this._overflowLevel; }
  get inletPipeDiameter()  { return this._inletPipeDiameter; }
  get outletPipeDiameter() { return this._outletPipeDiameter; }
  get surfaceArea()      { return this._surfaceArea; }
  get maxVol()           { return this._maxVol; }
  get maxVolAtOverflow() { return this._maxVolAtOverflow; }
  get minVolAtInflow()   { return this._minVolAtInflow; }
  get minVolAtOutflow()  { return this._minVolAtOutflow; }
  get minVol()           { return this._minVol; }
  get minHeightBasedOn() { return this._minHeightBasedOn; }

  /** Convert level (m from floor) → volume (m3). Negative levels clamp to 0. */
  volumeFromLevel(level) {
    return Math.max(level, 0) * this._surfaceArea;
  }

  /** Convert volume (m3) → level (m from floor). Negative volumes clamp to 0. */
  levelFromVolume(volume) {
    return Math.max(volume, 0) / this._surfaceArea;
  }

  /**
   * Plain-object snapshot mirroring the legacy `this.basin` shape so
   * getOutput / status code can keep using the same field names without
   * caring whether it's holding a class instance or a plain object.
   */
  snapshot() {
    return {
      volEmptyBasin: this._volEmptyBasin,
      heightBasin: this._heightBasin,
      inflowLevel: this._inflowLevel,
      outflowLevel: this._outflowLevel,
      overflowLevel: this._overflowLevel,
      inletPipeDiameter: this._inletPipeDiameter,
      outletPipeDiameter: this._outletPipeDiameter,
      surfaceArea: this._surfaceArea,
      maxVol: this._maxVol,
      maxVolAtOverflow: this._maxVolAtOverflow,
      minVolAtInflow: this._minVolAtInflow,
      minVolAtOutflow: this._minVolAtOutflow,
      minVol: this._minVol,
      minHeightBasedOn: this._minHeightBasedOn,
    };
  }
}

module.exports = BasinGeometry;
