// PumpingStation editor — interactive basin SVG (top of the editor).
// Places threshold lines, derived safety levels, zone labels, dead-volume
// band, and ordering warnings. Same formulas as
// specificClass._validateThresholdOrdering.

(function () {
  const ns = window.PSEditor = window.PSEditor || {};
  const fNum = (id) => ns.fNum(id);

  // viewBox y bounds of the tank rect (now 120,40)..(240,380); width
  // shrunk to 360 in the new side-panel layout. y-bounds unchanged.
  const DIAG = { topY: 40, botY: 380 };

  const yForLevel = (val, basinH) => {
    if (val == null || !basinH) return null;
    const y = DIAG.botY - (val / basinH) * (DIAG.botY - DIAG.topY);
    return Math.max(DIAG.topY - 8, Math.min(DIAG.botY + 8, y));
  };

  // Place a row — line, label, input, unit all share the same y.
  const placeItem = (id, y) => {
    const line  = document.getElementById(`ps-line-${id}`);
    const label = document.getElementById(`ps-label-${id}`);
    const unit  = document.getElementById(`ps-unit-${id}`);
    const fo    = document.getElementById(`ps-fo-${id}`);
    const sub   = document.getElementById(`ps-sub-${id}`);
    const lead  = document.getElementById(`ps-leader-${id}`);
    if (line)  { line.setAttribute('y1', y); line.setAttribute('y2', y); }
    if (label) label.setAttribute('y', y + 4);
    if (unit)  unit.setAttribute('y', y + 4);
    if (fo)    fo.setAttribute('y', y - 11);
    if (sub)   sub.setAttribute('y', y + 15);
    if (lead)  lead.setAttribute('visibility', 'hidden');
  };

  ns.basinDiagram = {
    redraw() {
      const basinH = fNum('basinHeight') || 5;

      const refLow  = fNum('outflowLevel');
      const dryPct  = fNum('dryRunThresholdPercent');
      const highPct = fNum('highVolumeSafetyThresholdPercent');
      const ovf     = fNum('overflowLevel');
      const dryLvl  = (refLow != null && dryPct != null) ? refLow * (1 + dryPct / 100) : null;
      const highLvl = (ovf    != null && highPct != null) ? ovf    * (highPct / 100)     : null;

      // Right-column stack. TWO anchors: basinHeight pinned at the rim,
      // outflowLevel pinned at its proportional y. Two passes (top-down +
      // bottom-up) maintain a minimum vertical gap.
      const items = [
        { id: 'basinHeight',   yIdeal: DIAG.topY,                                pinned: true },
        { id: 'overflowLevel', yIdeal: yForLevel(fNum('overflowLevel'), basinH) },
        { id: 'highVolumeSafetyLevel', yIdeal: yForLevel(highLvl, basinH) },
        { id: 'inflowLevelGuide', yIdeal: yForLevel(fNum('inflowLevel'), basinH) },
        { id: 'dryRunLevel',   yIdeal: yForLevel(dryLvl,                basinH) },
        { id: 'outflowLevel',  yIdeal: yForLevel(fNum('outflowLevel'),  basinH), pinned: true },
      ].filter(it => it.yIdeal != null);

      const GAP = 36;
      items.sort((a, b) => a.yIdeal - b.yIdeal);
      for (const it of items) it.y = it.yIdeal;
      for (let i = 1; i < items.length; i++) {
        if (items[i].pinned) continue;
        items[i].y = Math.max(items[i].y, items[i - 1].y + GAP);
      }
      for (let i = items.length - 2; i >= 0; i--) {
        if (items[i].pinned) continue;
        items[i].y = Math.min(items[i].y, items[i + 1].y - GAP);
      }
      for (const it of items) placeItem(it.id, it.y);

      // Zone labels show only when the gap between the bracketing
      // thresholds is at least MIN_ZONE_GAP px high — otherwise the label
      // collides with one of the threshold labels (which sit at threshold
      // y ±6 px text-height). 28 px keeps a 6 px clear gap above and
      // below the zone label.
      const MIN_ZONE_GAP = 28;
      const placeZone = (zoneId, topId, botId) => {
        const el = document.getElementById(`ps-zone-${zoneId}`);
        if (!el) return;
        const top = items.find(it => it.id === topId);
        const bot = items.find(it => it.id === botId);
        if (!top || !bot || (bot.y - top.y) < MIN_ZONE_GAP) {
          el.setAttribute('visibility', 'hidden'); return;
        }
        el.setAttribute('y', (top.y + bot.y) / 2 + 3);
        el.setAttribute('visibility', 'visible');
      };
      placeZone('spare',   'overflowLevel', 'highVolumeSafetyLevel');
      placeZone('sewage',  'highVolumeSafetyLevel', 'inflowLevelGuide');
      placeZone('buffer1', 'inflowLevelGuide', 'dryRunLevel');
      placeZone('buffer2', 'dryRunLevel', 'outflowLevel');
      const outflowPinned = items.find(it => it.id === 'outflowLevel');
      const deadLbl = document.getElementById('ps-zone-dead');
      if (deadLbl && outflowPinned && (DIAG.botY - outflowPinned.y) > 14) {
        deadLbl.setAttribute('y', (outflowPinned.y + DIAG.botY) / 2 + 3);
        deadLbl.setAttribute('visibility', 'visible');
      } else if (deadLbl) {
        deadLbl.setAttribute('visibility', 'hidden');
      }

      const inflowY = yForLevel(fNum('inflowLevel'), basinH);
      if (inflowY != null) {
        const line = document.getElementById('ps-line-inflowLevel');
        const lbl  = document.getElementById('ps-label-inflowLevel');
        const sub  = document.getElementById('ps-sub-inflowLevel');
        const fo   = document.getElementById('ps-fo-inflowLevel');
        const unit = document.getElementById('ps-unit-inflowLevel');
        if (line) { line.setAttribute('y1', inflowY); line.setAttribute('y2', inflowY); }
        if (lbl)  lbl.setAttribute('y', inflowY - 4);
        if (sub)  sub.setAttribute('y', inflowY + 8);
        if (fo)   fo.setAttribute('y', inflowY - 11);
        if (unit) unit.setAttribute('y', inflowY + 4);
      }

      const outflowItem = items.find(it => it.id === 'outflowLevel');
      const deadvol    = document.getElementById('ps-deadvol');
      if (deadvol && outflowItem) {
        deadvol.setAttribute('y', outflowItem.y);
        deadvol.setAttribute('height', Math.max(0, DIAG.botY - outflowItem.y));
      }

      // SVG labels — keep them short, side panel shows the numeric value.
      const dryLbl = document.getElementById('ps-label-dryRunLevel');
      if (dryLbl) dryLbl.textContent = 'dryRunLevel';
      const highLbl = document.getElementById('ps-label-highVolumeSafetyLevel');
      if (highLbl) highLbl.textContent = 'highVolumeSafety';

      // Side-panel read-only displays — number only ("m" is shown in the unit span).
      const fmt = (v) => Number.isFinite(v) ? v.toFixed(2) : '—';
      const d1 = document.getElementById('derived-dryRunLevel');
      if (d1) d1.textContent = fmt(dryLvl);
      const d2 = document.getElementById('derived-highVolumeSafetyLevel');
      if (d2) d2.textContent = fmt(highLvl);

      // Hierarchy validation. Soft '≤' relations follow the user's choice:
      // start ≤ inflow, max ≤ overflow, overflow ≤ basinHeight (equality OK).
      // dryRunLevel must be < startLevel strictly (otherwise the runtime
      // would trip dry-run before it could ramp).
      // Re-read the raw value (basinH falls back to 5 for diagram scaling;
      // here we want null when the user hasn't entered anything so the
      // ≤-checks below are skipped rather than false-flagged).
      const basinHraw = fNum('basinHeight');
      const start = fNum('startLevel');
      const hold  = fNum('holdLevel');
      const inlet = fNum('inflowLevel');
      const max   = fNum('maxLevel');
      const ovfl  = fNum('overflowLevel');
      const issues = [];
      const ok = (a, b, op) => {
        if (!Number.isFinite(a) || !Number.isFinite(b)) return true;
        return op === '<' ? a < b : a <= b;
      };
      if (Number.isFinite(refLow) && refLow <= 0)
        issues.push('outflowLevel must be > 0');
      if (!ok(dryLvl, start, '<'))
        issues.push(`dryRunLevel (${(dryLvl ?? NaN).toFixed(2)} m, derived) must be < startLevel — lower dryRun% or raise startLevel`);
      if (!ok(start, max, '<'))
        issues.push('startLevel must be < maxLevel');
      if (!ok(start, hold, '<='))
        issues.push('holdLevel must be ≥ startLevel (use startLevel for no hold band)');
      if (!ok(hold, max, '<'))
        issues.push('holdLevel must be < maxLevel');
      if (!ok(inlet, max, '<='))
        issues.push('inflowLevel must be ≤ maxLevel');
      if (!ok(max, ovfl, '<='))
        issues.push('maxLevel must be ≤ overflowLevel');
      if (!ok(ovfl, basinHraw, '<='))
        issues.push('overflowLevel must be ≤ basinHeight');

      // Visible ribbon above the basin diagram.
      const warnDiv = document.getElementById('ps-basin-validation');
      if (warnDiv) {
        if (issues.length) {
          warnDiv.innerHTML = '⚠ Fix before deploy:<ul style="margin:4px 0 0 18px;padding:0;">'
            + issues.map((i) => `<li>${i}</li>`).join('') + '</ul>';
          warnDiv.style.display = '';
        } else {
          warnDiv.style.display = 'none';
        }
      }
      // Legacy in-SVG warning text — kept for the small reminder inside
      // the diagram. Only shows the count.
      const warn = document.getElementById('ps-warning');
      if (warn) {
        if (issues.length) {
          warn.setAttribute('visibility', 'visible');
          warn.textContent = `⚠ ${issues.length} ordering issue${issues.length > 1 ? 's' : ''}`;
        } else {
          warn.setAttribute('visibility', 'hidden');
        }
      }
      window._psBasinValidationIssues = issues;
    },
  };
})();
