/* global React, SF */
// ============================================================
// Architecture map: nodes + SVG connectors + interactions
// ============================================================
const { useState, useRef, useEffect, useLayoutEffect } = React;
const TONE = { g:'var(--gw)', p:'var(--cg)', o:'var(--cw)', b:'var(--cs)', r:'var(--db)', t:'#0D9488', m:'#C026D3', e:'#64748B' };
const TONE_D = { g:'var(--gw-d)', p:'var(--cg-d)', o:'var(--cw-d)', b:'var(--cs-d)', r:'var(--db-d)', t:'#0B7A70', m:'#9B1EAA', e:'#475569' };

// rectangle border intersection toward target
function clip(cx, cy, hw, hh, tx, ty) {
  const dx = tx - cx, dy = ty - cy;
  if (dx === 0 && dy === 0) return [cx, cy];
  const sx = hw / Math.abs(dx || 1e-6), sy = hh / Math.abs(dy || 1e-6);
  const s = Math.min(sx, sy);
  return [cx + dx * s, cy + dy * s];
}

function ArchMap({ layoutId, openIds, onToggle, hoverNode, setHoverNode }) {
  const { systems, edges, layouts, Icon, orderMain } = SF;
  const layout = layouts[layoutId];
  const wrapRef = useRef(null);
  const [size, setSize] = useState({ w: 1000, h: 640 });
  const [hoverEdge, setHoverEdge] = useState(null);

  useLayoutEffect(() => {
    const el = wrapRef.current;
    if (!el) return;
    const ro = new ResizeObserver(() => {
      const r = el.getBoundingClientRect();
      setSize({ w: r.width, h: r.height });
    });
    ro.observe(el);
    return () => ro.disconnect();
  }, []);

  // Responsive scaling: each layout has a reference canvas size
  const REF_H = { pipeline:700, hub:750, lane:900 };
  const vw = 1440, vh = REF_H[layoutId] || 720;
  const rawScale = Math.min(size.w / vw, size.h / vh, 1);
  const scale = Math.max(rawScale, 0.35); // mobile min 35%
  const scaledW = Math.round(vw * scale);
  const overflowX = scaledW > size.w + 1; // mobile: needs horizontal scroll

  // padded fraction → px/py use the virtual (reference) canvas dimensions
  const px = (f) => 40 + f * (vw - 80);
  const py = (f) => 30 + f * (vh - 60);
  const center = (id) => {
    const p = layout.pos[id];
    return [px(p.x), py(p.y)];
  };
  const half = (id) => (systems[id].hub ? [76, 86] : [90, 84]);

  // which edges visible for this layout: hub spokes only emphasised in hub layout but shown subtle everywhere
  const visEdges = edges;

  // highlight sets
  const connectedEdges = new Set();
  const connectedNodes = new Set();
  if (hoverNode) edges.forEach(e => {
    if (e.from === hoverNode || e.to === hoverNode) {
      connectedEdges.add(e.id); connectedNodes.add(e.from); connectedNodes.add(e.to);
    }
  });

  function edgeState(e) {
    if (hoverEdge) return hoverEdge === e.id ? 'on' : 'dim';
    if (hoverNode) return connectedEdges.has(e.id) ? 'on' : 'dim';
    return e.kind === 'hub' ? 'sub' : e.kind === 'erp' ? 'erp-sub' : 'normal';
  }
  function nodeDim(id) {
    if (hoverEdge) { const e = edges.find(x => x.id === hoverEdge); return !(e.from === id || e.to === id); }
    if (hoverNode) return !connectedNodes.has(id);
    return false;
  }

  // build path + label pos for an edge
  function geom(e) {
    const [ax0, ay0] = center(e.from), [bx0, by0] = center(e.to);
    const [fhw, fhh] = half(e.from), [thw, thh] = half(e.to);
    const [ax, ay] = clip(ax0, ay0, fhw + 7, fhh + 7, bx0, by0);
    const [bx, by] = clip(bx0, by0, thw + 9, thh + 9, ax0, ay0);
    const mx = (ax + bx) / 2, my = (ay + by) / 2;
    const dx = bx - ax, dy = by - ay;
    const len = Math.hypot(dx, dy) || 1;
    const nx = -dy / len, ny = dx / len; // perpendicular
    const bend = (layout.bend && layout.bend[e.id]) || 0;
    const off = bend * len;
    const cx1 = ax + dx * 0.33 + nx * off, cy1 = ay + dy * 0.33 + ny * off;
    const cx2 = ax + dx * 0.67 + nx * off, cy2 = ay + dy * 0.67 + ny * off;
    const d = `M ${ax} ${ay} C ${cx1} ${cy1} ${cx2} ${cy2} ${bx} ${by}`;
    // label sits on the arc apex: midpoint + perpendicular * (0.75 of control offset)
    const lx = mx + nx * off * 0.75;
    const ly = my + ny * off * 0.75 + ((layout.labelDy && layout.labelDy[e.id]) || 0);
    return { d, lx, ly };
  }

  const showLabels = layoutId !== 'hub' ? true : true;

  return (
    React.createElement('div', { className: 'canvas-wrap', ref: wrapRef,
      style: overflowX ? { overflowX:'auto', WebkitOverflowScrolling:'touch' } : undefined },
      React.createElement('div', {
        style: overflowX
          ? { width:vw, height:vh, zoom:scale }
          : { position:'absolute', top:0, left:Math.round((size.w-scaledW)/2), width:vw, height:vh, transform:`scale(${scale})`, transformOrigin:'0 0' }
      },
      // lanes (swimlane layout)
      (layout.lanes || []).map((ln, i) =>
        React.createElement('div', {
          key: 'lane'+i, className: 'lane-band',
          style: {
            position:'absolute', left: 24, right: 24,
            top: py(ln.y0), height: py(ln.y1)-py(ln.y0),
            borderRadius: 22,
            background: ln.tone==='b' ? 'rgba(62,114,224,.04)' : ln.tone==='m' ? 'rgba(192,38,211,.03)' : ln.tone==='e' ? 'rgba(100,116,139,.05)' : 'rgba(120,130,150,.045)',
            border: ln.tone==='e' ? '1px dashed rgba(100,116,139,.30)' : '1px dashed rgba(120,130,150,.18)',
            zIndex: 1,
          }
        },
          React.createElement('span', { style: {
            position:'absolute', left:16, top:12, fontSize:11, fontWeight:800,
            letterSpacing:'.5px', color:'var(--ink-4)', textTransform:'uppercase'
          } }, ln.label)
        )
      ),

      // SVG edges
      React.createElement('svg', { className: 'edges', width: vw, height: vh },
        React.createElement('defs', null,
          ...['g','p','o','b','r','t','m','e'].map(tn =>
            React.createElement('marker', {
              key: tn, id: 'ah-'+tn, viewBox:'0 0 10 10', refX:8, refY:5,
              markerWidth:7, markerHeight:7, orient:'auto-start-reverse'
            }, React.createElement('path', { d:'M0 0 L9 5 L0 10 z', fill: TONE[tn] }))
          )
        ),
        visEdges.map(e => {
          const g = geom(e);
          const st = edgeState(e);
          const tn = e.tone;
          const dash = e.kind === 'flow' ? null : e.kind === 'hub' ? '2 7' : e.kind === 'erp' ? '4 5' : '7 7';
          let w = e.kind === 'flow' ? 3 : e.kind === 'hub' ? 1.6 : e.kind === 'erp' ? 1.5 : 2.4;
          let op = 1;
          if (st === 'on') { w += 1.2; op = 1; }
          else if (st === 'dim') op = 0.1;
          else if (st === 'sub') op = 0.32;
          else if (st === 'erp-sub') op = 0.40;
          return React.createElement('g', { key: e.id },
            React.createElement('path', {
              className:'edge-path', d: g.d, stroke: TONE[tn], strokeWidth: w,
              strokeDasharray: dash || undefined, opacity: op,
              markerEnd: e.kind!=='hub' ? `url(#ah-${tn})` : undefined,
            }),
            React.createElement('path', {
              className:'edge-hit', d: g.d,
              onMouseEnter: () => setHoverEdge(e.id),
              onMouseLeave: () => setHoverEdge(null),
            })
          );
        })
      ),

      // edge labels (HTML, on top)
      showLabels && visEdges.filter(e => e.kind !== 'hub').map(e => {
        const g = geom(e);
        const st = edgeState(e);
        const tn = e.tone;
        return React.createElement('div', {
          key: 'lb'+e.id,
          className: 'edge-label' + (st === 'dim' ? ' dim' : ''),
          style: { left: g.lx, top: g.ly, opacity: st==='sub' ? .55 : st==='erp-sub' ? .48 : undefined },
          onMouseEnter: () => setHoverEdge(e.id),
          onMouseLeave: () => setHoverEdge(null),
          title: e.pass,
        },
          e.num != null
            ? React.createElement('span', { className:'edge-num', style:{ background: TONE[tn] } }, e.num)
            : React.createElement('span', { style:{
                width:8, height:8, borderRadius:9, background: TONE[tn], marginLeft:4, flex:'0 0 auto'
              }}),
          React.createElement('span', null, e.label)
        );
      }),

      // nodes
      Object.values(systems).map(s => {
        const [cx, cy] = center(s.id);
        const open = openIds.includes(s.id);
        const dim = nodeDim(s.id);
        return React.createElement('div', {
          key: s.id,
          className: 'node' + (s.hub ? ' hub' : '') + (s.future ? ' future' : '') + (open ? ' active' : '') + (dim ? ' dim' : ''),
          style: {
            left: cx, top: cy,
            '--c': s.cssC, '--tint': s.tint, '--soft': s.soft,
          },
          onMouseEnter: () => setHoverNode(s.id),
          onMouseLeave: () => setHoverNode(null),
          onClick: () => onToggle(s.id),
        },
          React.createElement('div', { className:'node-bar' }),
          React.createElement('div', { className:'node-body' },
            React.createElement('div', { className:'node-head' },
              React.createElement('div', { className:'node-icon' }, React.createElement(Icon, { name: s.icon })),
              React.createElement('div', { className:'node-title' },
                React.createElement('b', null, s.name),
                React.createElement('span', null, s.host)
              )
            ),
            s.hub
              ? React.createElement('div', { className:'pulse' },
                  React.createElement('i'), '即時聚合 4 系統')
              : React.createElement('div', { className:'node-roles' },
                  s.roles.map(r => React.createElement('span', { key:r, className:'node-role' }, r))
                ),
            !s.hub && React.createElement('div', { className:'node-cta' },
              React.createElement('span', null, open ? '面板已開啟' : s.desc),
              s.future
                ? React.createElement('span', { style:{
                    fontSize:9.5, fontWeight:800, color: s.cssC,
                    background: s.tint, padding:'2px 8px', borderRadius:99,
                    border:'1px solid rgba(0,0,0,.08)', letterSpacing:'.3px',
                  }}, '規劃中')
                : React.createElement('span', { className:'open' },
                    React.createElement('span', null, open ? '檢視中' : '開啟'),
                    React.createElement(Icon, { name: open ? 'check' : 'arrow', style:{ width:13, height:13 } })
                  )
            )
          )
        );
      })
      ) // end inner scale wrapper
    )
  );
}
window.ArchMap = ArchMap;
