// PumpingStation editor — dynamic input bounds.
// Sets HTML5 min/max attributes on every level and percent input based on
// the current values of related inputs, so the up/down arrows stop at
// values that respect the basin hierarchy:
//
//   0 < outflowLevel < dryRunLevel < startLevel < maxLevel ≤ overflowLevel ≤ basinHeight
//   0 < outflowLevel < inflowLevel < overflowLevel ≤ basinHeight
//
// startLevel is intentionally NOT clamped against inflowLevel: pushing
// startLevel above the gravity-feed inlet is the "buffer in the sewer"
// configuration where upstream pipe storage absorbs flow before pumping
// engages. The level-based ramp foot is max(startLevel, inflowLevel) so
// either ordering is valid.
//
// The user can still type out-of-range values via the keyboard (HTML5
// min/max only constrain the spinner). The validation ribbons in
// basin-diagram.js and mode-preview.js catch typed violations and the
// oneditsave handler blocks Deploy until they're resolved.

(function () {
  const ns = window.PSEditor = window.PSEditor || {};
  const fNum = (id) => ns.fNum(id);
  const EPS = 0.001; // smallest meaningful step (mm-precision)

  const setBounds = (id, min, max) => {
    const el = document.getElementById(`node-input-${id}`);
    if (!el) return;
    if (Number.isFinite(min)) el.setAttribute('min', String(min));
    else el.removeAttribute('min');
    if (Number.isFinite(max)) el.setAttribute('max', String(max));
    else el.removeAttribute('max');
  };

  ns.bounds = {
    apply() {
      const basinHeight = fNum('basinHeight');
      const outflow     = fNum('outflowLevel');
      const dryPct      = fNum('dryRunThresholdPercent');
      const start       = fNum('startLevel');
      const inlet       = fNum('inflowLevel');
      const max         = fNum('maxLevel');
      const overflow    = fNum('overflowLevel');
      const shiftEnabled = !!document.getElementById('node-input-enableShiftedRamp')?.checked;

      // Derived dryRunLevel (lower bound for startLevel).
      const dryRun = (Number.isFinite(outflow) && Number.isFinite(dryPct))
        ? outflow * (1 + dryPct / 100) : null;

      // Geometry — basin envelope.
      setBounds('basinHeight',   EPS, undefined);
      setBounds('basinVolume',   EPS, undefined);

      // Levels (each capped by the next-higher level if defined).
      setBounds('outflowLevel',  EPS,
        Number.isFinite(start) && Number.isFinite(dryPct)
          ? start / (1 + dryPct / 100) - EPS  // keep dryRun < start
          : (start ?? inlet ?? max ?? overflow ?? basinHeight));

      setBounds('startLevel',
        Number.isFinite(dryRun) ? dryRun + EPS : EPS,
        max ?? overflow ?? basinHeight);

      setBounds('inflowLevel',
        EPS,
        max ?? overflow ?? basinHeight);

      setBounds('maxLevel',
        inlet ?? start ?? EPS,
        overflow ?? basinHeight);

      setBounds('overflowLevel',
        max ?? inlet ?? start ?? EPS,
        basinHeight);

      // stopLevel — explicit pump-off threshold. Must sit between
      // dryRunLevel and startLevel (so it can be reached during draining
      // before pumps re-engage).
      setBounds('stopLevel',
        Number.isFinite(dryRun) ? dryRun + EPS : EPS,
        start ?? inlet ?? max ?? overflow ?? basinHeight);

      // holdLevel — 0 % ramp foot. Defaults to startLevel (no hold band);
      // when raised above startLevel, pumps engage at startLevel but emit
      // 0 % across [startLevel, holdLevel] before the ramp begins. Bounds:
      // startLevel ≤ holdLevel < maxLevel.
      setBounds('holdLevel',
        Number.isFinite(start) ? start : EPS,
        max ?? overflow ?? basinHeight);

      // Shift inputs (only relevant when shifted ramp enabled).
      if (shiftEnabled) {
        setBounds('shiftLevel',
          Number.isFinite(start) ? start : EPS,
          max ?? overflow ?? basinHeight);
        setBounds('shiftArmPercent', 1, 100);
      }

      // Percentages.
      // dryRun% capped so dryRunLevel ≤ startLevel.
      let dryMax = 99;
      if (Number.isFinite(start) && Number.isFinite(outflow) && outflow > 0) {
        dryMax = Math.max(0, Math.min(99, ((start / outflow) - 1) * 100));
      }
      setBounds('dryRunThresholdPercent', 0, dryMax);

      // highVol% bounded (1, 100). Equal to 100 means no margin to overflow.
      setBounds('highVolumeSafetyThresholdPercent', 1, 100);
    },
  };
})();
