'use strict';

// iconHelpers.js — shared visual layer for EVOLV editor menus.
//
// The other menu modules (logger, physicalPosition, …) render their HTML
// as plain Node-RED form rows with native <select>/<input> controls. This
// module emits a single client-side helper bundle (`window.EVOLV.iconHelpers`)
// that those menus call from their `initVisuals(node)` step to upgrade the
// native controls in-place to icon cards.
//
// The native controls stay in the DOM (hidden) so Node-RED's load/save
// path is untouched — clicks on the cards mirror back into the original
// <select>/<input>.

class IconHelpers {
  static getClientInitCode() {
    // Single IIFE so multiple menus on the same editor session share one
    // copy of the helpers + one <style> tag.
    return `
      window.EVOLV = window.EVOLV || {};
      if (!window.EVOLV.iconHelpers) {
        window.EVOLV.iconHelpers = (function () {
          const BLUE = '#1F4E79';
          const STEEL = '#607484';
          const UNIT = '#50a8d9';
          const RED = '#B03A2E';
          const AMBER = '#B7791F';

          // ---- CSS (injected once) -----------------------------------
          const CSS_ID = 'evolv-icon-pickers-css';
          if (!document.getElementById(CSS_ID)) {
            const style = document.createElement('style');
            style.id = CSS_ID;
            style.textContent = [
              '.evolv-icon-picker { display:flex; gap:6px; flex-wrap:wrap; margin:6px 0 8px 0; }',
              '.evolv-icon-option {',
              '  width:72px; height:72px; box-sizing:border-box;',
              '  border:2px solid #d0d0d0; border-radius:4px; background:#fafafa;',
              '  padding:4px; cursor:pointer; user-select:none;',
              '  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:2px;',
              '  transition:border-color 80ms ease-out, background 80ms ease-out, opacity 80ms ease-out;',
              '}',
              '.evolv-icon-option:hover { border-color:#86bbdd; background:#f5fafd; }',
              '.evolv-icon-option:focus { outline:2px solid #1F4E79; outline-offset:2px; }',
              '.evolv-icon-option-on { border-color:#50a8d9; background:#eaf4fb; }',
              '.evolv-icon-glyph { width:100%; height:46px; display:flex; align-items:center; justify-content:center; }',
              '.evolv-icon-option svg { width:100%; height:100%; display:block; }',
              '.evolv-icon-label { font-size:10px; line-height:1; font-weight:600; color:#333; white-space:nowrap; letter-spacing:0; }',
              '.evolv-icon-option:not(.evolv-icon-option-on) .evolv-icon-label { color:#888; }',
              '.evolv-icon-option-on .evolv-off-cross { display:none; }',
              '.evolv-native-hidden { position:absolute !important; opacity:0 !important; width:1px !important; height:1px !important; pointer-events:none !important; }',
              '.evolv-native-row-compact label { display:none; }',
              '.evolv-compact-row { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin:6px 0 8px 0; }',
              '.evolv-log-toggle:not(.evolv-icon-option-on) svg .evolv-log-symbol,',
              '.evolv-distance-toggle:not(.evolv-icon-option-on) svg .evolv-ruler-body { opacity:0.45; filter:grayscale(1); }',
            ].join('\\n');
            document.head.appendChild(style);
          }

          // ---- SVG library (inline, no external assets) --------------
          const SVG = {
            error: \`
              <svg viewBox="0 0 80 58" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
                <rect x="18" y="11" width="44" height="36" rx="3" fill="#fff" stroke="\${STEEL}" stroke-width="2.4"/>
                <circle cx="40" cy="29" r="13" fill="#fff" stroke="\${RED}" stroke-width="3"/>
                <line x1="34" y1="23" x2="46" y2="35" stroke="\${RED}" stroke-width="3.4" stroke-linecap="round"/>
                <line x1="46" y1="23" x2="34" y2="35" stroke="\${RED}" stroke-width="3.4" stroke-linecap="round"/>
              </svg>\`,
            warn: \`
              <svg viewBox="0 0 80 58" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
                <rect x="18" y="11" width="44" height="36" rx="3" fill="#fff" stroke="\${STEEL}" stroke-width="2.4"/>
                <path d="M40 17 L54 41 H26 Z" fill="#fff" stroke="\${AMBER}" stroke-width="3" stroke-linejoin="round"/>
                <line x1="40" y1="25" x2="40" y2="33" stroke="\${AMBER}" stroke-width="3" stroke-linecap="round"/>
                <circle cx="40" cy="38" r="2.2" fill="\${AMBER}"/>
              </svg>\`,
            info: \`
              <svg viewBox="0 0 80 58" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
                <rect x="18" y="11" width="44" height="36" rx="3" fill="#fff" stroke="\${STEEL}" stroke-width="2.4"/>
                <circle cx="40" cy="29" r="13" fill="#fff" stroke="\${BLUE}" stroke-width="3"/>
                <line x1="40" y1="28" x2="40" y2="37" stroke="\${BLUE}" stroke-width="3.2" stroke-linecap="round"/>
                <circle cx="40" cy="22" r="2.4" fill="\${BLUE}"/>
              </svg>\`,
            debug: \`
              <svg viewBox="0 0 80 58" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
                <rect x="13" y="12" width="54" height="34" rx="3" fill="#fff" stroke="\${STEEL}" stroke-width="2.4"/>
                <path d="M20 34 H29 L33 24 L40 39 L46 29 H59" fill="none" stroke="\${BLUE}" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"/>
                <circle cx="59" cy="29" r="3" fill="\${UNIT}" stroke="#fff" stroke-width="1"/>
              </svg>\`,
            logToggle: \`
              <svg viewBox="0 0 80 58" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
                <g class="evolv-log-symbol">
                  <rect x="10" y="10" width="60" height="38" rx="3" fill="#1F2933" stroke="\${STEEL}" stroke-width="2.4"/>
                  <path d="M18 22 L26 29 L18 36" fill="none" stroke="#7ED957" stroke-width="2.8" stroke-linecap="round" stroke-linejoin="round"/>
                  <line x1="30" y1="38" x2="50" y2="38" stroke="#7ED957" stroke-width="2.6" stroke-linecap="round"/>
                </g>
                <g class="evolv-off-cross" stroke="\${RED}" stroke-width="4.5" stroke-linecap="round">
                  <line x1="14" y1="12" x2="66" y2="46"/>
                </g>
              </svg>\`,
            // Position icons — depict the PARENT equipment (pump volute +
            // motor stub) plus a sensor marker located in the suction pipe
            // (upstream), atop the equipment (atEquipment), or in the
            // discharge pipe (downstream). Flow direction: left → right.
            upstream: \`
              <svg viewBox="0 0 80 58" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
                <!-- suction pipe + flow arrow -->
                <rect x="2" y="26" width="40" height="10" fill="#dde7f0" stroke="\${BLUE}" stroke-width="1.6"/>
                <line x1="6" y1="31" x2="34" y2="31" stroke="\${BLUE}" stroke-width="1.6"/>
                <polygon points="32,27 32,35 39,31" fill="\${BLUE}"/>
                <!-- sensor marker on suction pipe -->
                <line x1="20" y1="14" x2="20" y2="26" stroke="\${RED}" stroke-width="1.8"/>
                <circle cx="20" cy="11" r="5" fill="#fff" stroke="\${RED}" stroke-width="2"/>
                <circle cx="20" cy="11" r="1.6" fill="\${RED}"/>
                <!-- pump (volute) + impeller hint + motor stub -->
                <circle cx="60" cy="31" r="13" fill="#fff" stroke="\${STEEL}" stroke-width="2"/>
                <path d="M 60 22 Q 68 26 68 31 Q 68 36 60 40 Q 52 36 52 31 Q 52 26 60 22" fill="none" stroke="#86bbdd" stroke-width="1.3"/>
                <rect x="55" y="13" width="10" height="6" fill="\${STEEL}" stroke="#333" stroke-width="0.8"/>
              </svg>\`,
            atEquipment: \`
              <svg viewBox="0 0 80 58" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
                <!-- inlet stub -->
                <rect x="2" y="26" width="22" height="10" fill="#dde7f0" stroke="\${BLUE}" stroke-width="1.6"/>
                <line x1="4" y1="31" x2="20" y2="31" stroke="\${BLUE}" stroke-width="1.6"/>
                <polygon points="18,27 18,35 24,31" fill="\${BLUE}"/>
                <!-- outlet stub -->
                <rect x="56" y="26" width="22" height="10" fill="#dde7f0" stroke="\${BLUE}" stroke-width="1.6"/>
                <line x1="58" y1="31" x2="74" y2="31" stroke="\${BLUE}" stroke-width="1.6"/>
                <polygon points="72,27 72,35 78,31" fill="\${BLUE}"/>
                <!-- pump (volute) + impeller hint -->
                <circle cx="40" cy="31" r="13" fill="#fff" stroke="\${STEEL}" stroke-width="2"/>
                <path d="M 40 22 Q 48 26 48 31 Q 48 36 40 40 Q 32 36 32 31 Q 32 26 40 22" fill="none" stroke="#86bbdd" stroke-width="1.3"/>
                <!-- sensor marker AT equipment (top, on the volute itself) -->
                <line x1="40" y1="6"  x2="40" y2="18" stroke="\${RED}" stroke-width="1.8"/>
                <circle cx="40" cy="6" r="5" fill="#fff" stroke="\${RED}" stroke-width="2"/>
                <circle cx="40" cy="6" r="1.6" fill="\${RED}"/>
              </svg>\`,
            downstream: \`
              <svg viewBox="0 0 80 58" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
                <!-- pump (volute) + impeller hint + motor stub -->
                <circle cx="20" cy="31" r="13" fill="#fff" stroke="\${STEEL}" stroke-width="2"/>
                <path d="M 20 22 Q 28 26 28 31 Q 28 36 20 40 Q 12 36 12 31 Q 12 26 20 22" fill="none" stroke="#86bbdd" stroke-width="1.3"/>
                <rect x="15" y="13" width="10" height="6" fill="\${STEEL}" stroke="#333" stroke-width="0.8"/>
                <!-- discharge pipe + flow arrow -->
                <rect x="38" y="26" width="40" height="10" fill="#dde7f0" stroke="\${BLUE}" stroke-width="1.6"/>
                <line x1="42" y1="31" x2="70" y2="31" stroke="\${BLUE}" stroke-width="1.6"/>
                <polygon points="68,27 68,35 75,31" fill="\${BLUE}"/>
                <!-- sensor marker on discharge pipe -->
                <line x1="60" y1="14" x2="60" y2="26" stroke="\${RED}" stroke-width="1.8"/>
                <circle cx="60" cy="11" r="5" fill="#fff" stroke="\${RED}" stroke-width="2"/>
                <circle cx="60" cy="11" r="1.6" fill="\${RED}"/>
              </svg>\`,
            // Output-format icons — used by the shared
            // renderOutputFormatPicker helper so every node renders the
            // process/json/csv/influxdb dropdowns with the same visuals.
            outputProcess: \`
              <svg viewBox="0 0 80 58" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
                <rect x="10" y="14" width="20" height="30" rx="2" fill="#f7fafc" stroke="\${STEEL}" stroke-width="2.4"/>
                <rect x="50" y="14" width="20" height="30" rx="2" fill="#f7fafc" stroke="\${STEEL}" stroke-width="2.4"/>
                <line x1="30" y1="29" x2="46" y2="29" stroke="\${BLUE}" stroke-width="3" stroke-linecap="round"/>
                <path d="M42 24 L48 29 L42 34" fill="none" stroke="\${BLUE}" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
              </svg>\`,
            outputJson: \`
              <svg viewBox="0 0 80 58" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
                <g fill="none" stroke="\${BLUE}" stroke-width="3.4" stroke-linecap="round" stroke-linejoin="round">
                  <path d="M30 14 C22 16 22 26 27 29 C22 32 22 42 30 44"/>
                  <path d="M50 14 C58 16 58 26 53 29 C58 32 58 42 50 44"/>
                </g>
                <g fill="\${STEEL}">
                  <circle cx="36" cy="29" r="2.2"/>
                  <circle cx="44" cy="29" r="2.2"/>
                </g>
              </svg>\`,
            outputCsv: \`
              <svg viewBox="0 0 80 58" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
                <rect x="12" y="12" width="56" height="34" rx="2" fill="#fff" stroke="\${STEEL}" stroke-width="2.4"/>
                <line x1="12" y1="22" x2="68" y2="22" stroke="\${STEEL}" stroke-width="2"/>
                <g stroke="\${STEEL}" stroke-width="1.6">
                  <line x1="12" y1="34" x2="68" y2="34"/>
                  <line x1="31" y1="12" x2="31" y2="46"/>
                  <line x1="49" y1="12" x2="49" y2="46"/>
                </g>
              </svg>\`,
            outputInflux: \`
              <svg viewBox="0 0 80 58" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
                <ellipse cx="40" cy="15" rx="22" ry="6" fill="#f7fafc" stroke="\${STEEL}" stroke-width="2.4"/>
                <path d="M18 15 V42 C18 46 28 49 40 49 C52 49 62 46 62 42 V15" fill="#f7fafc" stroke="\${STEEL}" stroke-width="2.4"/>
                <path d="M18 28 C26 32 54 32 62 28" fill="none" stroke="\${STEEL}" stroke-width="1.6" opacity="0.6"/>
                <path d="M22 39 L30 32 L38 41 L46 34 L54 38" fill="none" stroke="\${BLUE}" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"/>
              </svg>\`,
            distance: \`
              <svg viewBox="0 0 80 58" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
                <g class="evolv-ruler-body">
                  <rect x="12" y="22" width="56" height="14" rx="1.5" fill="#fff" stroke="\${STEEL}" stroke-width="2.4"/>
                  <g stroke="\${STEEL}" stroke-width="1.8" stroke-linecap="round">
                    <line x1="20" y1="22" x2="20" y2="30"/>
                    <line x1="28" y1="22" x2="28" y2="27"/>
                    <line x1="36" y1="22" x2="36" y2="30"/>
                    <line x1="44" y1="22" x2="44" y2="27"/>
                    <line x1="52" y1="22" x2="52" y2="30"/>
                    <line x1="60" y1="22" x2="60" y2="27"/>
                  </g>
                </g>
                <g class="evolv-off-cross" stroke="\${RED}" stroke-width="4.5" stroke-linecap="round">
                  <line x1="16" y1="14" x2="64" y2="46"/>
                </g>
              </svg>\`,
          };

          // ---- Helpers -----------------------------------------------
          function dispatchChange(el) {
            el.dispatchEvent(new Event('change', { bubbles: true }));
          }

          // renderSelectPicker: replace a native <select> with a row of
          // icon cards. labels object maps option.value → display string.
          function renderSelectPicker(select, holder, icons, labels) {
            if (!select || !holder || holder.dataset.evolvReady === '1') return;
            holder.dataset.evolvReady = '1';
            select.classList.add('evolv-native-hidden');

            const options = Array.from(select.options).map((option) => ({
              value: option.value,
              title: option.textContent || option.value,
              label: (labels && labels[option.value]) || option.textContent || option.value,
              svg: icons[option.value],
            })).filter((option) => option.svg);

            holder.innerHTML = options.map((option) => (
              '<div class="evolv-icon-option" data-value="' + option.value + '" role="radio" tabindex="0"' +
              ' aria-label="' + option.title + '" aria-checked="false" title="' + option.title + '">' +
              '  <div class="evolv-icon-glyph">' + option.svg + '</div>' +
              '  <div class="evolv-icon-label">' + option.label + '</div>' +
              '</div>'
            )).join('');

            const buttons = Array.from(holder.querySelectorAll('.evolv-icon-option'));
            function sync() {
              const current = select.value || (options[0] && options[0].value) || '';
              for (const button of buttons) {
                const on = button.getAttribute('data-value') === current;
                button.classList.toggle('evolv-icon-option-on', on);
                button.setAttribute('aria-checked', String(on));
              }
            }
            function pick(value) {
              select.value = value;
              dispatchChange(select);
              sync();
            }
            for (const button of buttons) {
              button.addEventListener('click', () => pick(button.getAttribute('data-value')));
              button.addEventListener('keydown', (event) => {
                if (event.key === ' ' || event.key === 'Enter') {
                  event.preventDefault();
                  pick(button.getAttribute('data-value'));
                }
              });
            }
            select.addEventListener('change', sync);
            sync();
          }

          // renderToggle: replace a checkbox with a single icon card whose
          // label flips between {on, off}. Passing a string for label
          // uses the same string for both states.
          function renderToggle(checkbox, holder, svg, label) {
            if (!checkbox || !holder || holder.dataset.evolvReady === '1') return;
            holder.dataset.evolvReady = '1';
            checkbox.classList.add('evolv-native-hidden');
            const labels = typeof label === 'string' ? { on: label, off: label } : label;
            holder.innerHTML =
              '<div class="evolv-icon-glyph">' + svg + '</div>' +
              '<div class="evolv-icon-label">' + labels.off + '</div>';
            const labelEl = holder.querySelector('.evolv-icon-label');

            function sync() {
              const on = checkbox.checked;
              holder.classList.toggle('evolv-icon-option-on', on);
              holder.setAttribute('aria-checked', String(on));
              if (labelEl) labelEl.textContent = on ? labels.on : labels.off;
            }
            function toggle() {
              checkbox.checked = !checkbox.checked;
              dispatchChange(checkbox);
              sync();
            }
            holder.addEventListener('click', toggle);
            holder.addEventListener('keydown', (event) => {
              if (event.key === ' ' || event.key === 'Enter') {
                event.preventDefault();
                toggle();
              }
            });
            checkbox.addEventListener('change', sync);
            sync();
          }

          // renderOutputFormatPicker: shared widget for the process &
          // dbase output-format <select>s carried by most EVOLV nodes.
          // Encapsulates the icon set + labels so every node renders the
          // same visuals. Pass the native <select> and an empty holder
          // <div class="evolv-icon-picker">.
          const OUTPUT_FORMAT_ICONS = {
            process:  SVG.outputProcess,
            json:     SVG.outputJson,
            csv:      SVG.outputCsv,
            influxdb: SVG.outputInflux,
          };
          const OUTPUT_FORMAT_LABELS = {
            process:  'Process',
            json:     'JSON',
            csv:      'CSV',
            influxdb: 'Influx',
          };
          function renderOutputFormatPicker(select, holder) {
            renderSelectPicker(select, holder, OUTPUT_FORMAT_ICONS, OUTPUT_FORMAT_LABELS);
          }

          // upgradeOutputFormatSelects: idempotent platform-wide upgrade.
          // Scans the open editor dialog for the two canonical output-format
          // selects and replaces each with the icon picker. Skips selects
          // that are already upgraded (class evolv-native-hidden) or that
          // already have a sibling picker placed by the node's HTML.
          // Called from MenuManager's initEditor wrapper so every node
          // inherits the picker without per-node template edits.
          function upgradeOutputFormatSelects() {
            const specs = [
              { id: 'node-input-processOutputFormat', aria: 'Process output format' },
              { id: 'node-input-dbaseOutputFormat',   aria: 'Database output format' }
            ];
            specs.forEach((spec) => {
              const select = document.getElementById(spec.id);
              if (!select) return;
              if (select.classList && select.classList.contains('evolv-native-hidden')) return;
              const parent = select.parentNode;
              if (!parent) return;
              // Skip if a sibling picker already exists (manual wiring).
              const siblings = parent.children || [];
              for (let i = 0; i < siblings.length; i += 1) {
                const sib = siblings[i];
                if (sib !== select && sib.classList && sib.classList.contains('evolv-icon-picker')) return;
              }
              const holder = document.createElement('div');
              holder.className = 'evolv-icon-picker';
              holder.setAttribute('role', 'radiogroup');
              holder.setAttribute('aria-label', spec.aria);
              parent.appendChild(holder);
              renderOutputFormatPicker(select, holder);
            });
          }

          return { SVG, renderSelectPicker, renderToggle, renderOutputFormatPicker, upgradeOutputFormatSelects };
        })();
      }
    `;
  }
}

module.exports = IconHelpers;
