/* global React, SUMMIT */
// ProcessMap — the clickable canvas: swimlanes, nodes, orthogonal SVG
// connectors, handoff badges, decision branches, zoom.

const ROLE_TAG = {
  owner: 'Marcus · Owner',
  coord: 'Jess · Coordinator',
  foreman: 'Dave · Foreman',
  external: 'Homeowner / Apex',
};

// ---- connector geometry ---------------------------------------------------
function anchorPoint(r, side) {
  switch (side) {
    case 'right': return { x: r.x + r.w, y: r.y + r.h / 2, dx: 1, dy: 0 };
    case 'left': return { x: r.x, y: r.y + r.h / 2, dx: -1, dy: 0 };
    case 'top': return { x: r.x + r.w / 2, y: r.y, dx: 0, dy: -1 };
    case 'bottom': return { x: r.x + r.w / 2, y: r.y + r.h, dx: 0, dy: 1 };
    default: return { x: r.x, y: r.y, dx: 0, dy: 0 };
  }
}

function buildPath(from, to, fromSide, toSide) {
  const S = 22;
  const a = anchorPoint(from, fromSide);
  const b = anchorPoint(to, toSide);
  const p0 = { x: a.x, y: a.y };
  const p1 = { x: a.x + a.dx * S, y: a.y + a.dy * S };
  const p3 = { x: b.x, y: b.y };
  const p2 = { x: b.x + b.dx * S, y: b.y + b.dy * S };

  const fromH = a.dx !== 0;
  const toH = b.dx !== 0;
  let pts;
  let mid;
  if (fromH && toH) {
    const mx = (p1.x + p2.x) / 2;
    pts = [p0, p1, { x: mx, y: p1.y }, { x: mx, y: p2.y }, p2, p3];
    mid = { x: mx, y: (p1.y + p2.y) / 2 };
  } else if (!fromH && !toH) {
    const my = (p1.y + p2.y) / 2;
    pts = [p0, p1, { x: p1.x, y: my }, { x: p2.x, y: my }, p2, p3];
    mid = { x: (p1.x + p2.x) / 2, y: my };
  } else if (fromH && !toH) {
    const corner = { x: p2.x, y: p1.y };
    pts = [p0, p1, corner, p2, p3];
    mid = corner;
  } else {
    const corner = { x: p1.x, y: p2.y };
    pts = [p0, p1, corner, p2, p3];
    mid = corner;
  }
  const d = pts.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x.toFixed(1)},${p.y.toFixed(1)}`).join(' ');
  return { d, mid };
}

// ---- Node card ------------------------------------------------------------
function NodeCard({ node, role, selected, onClick, registerRef }) {
  const isDecision = node.kind === 'decision';
  const isMilestone = node.kind === 'milestone';
  const base = {
    position: 'absolute', left: node.x, top: node.y, width: node.w,
    boxSizing: 'border-box', cursor: 'pointer', textAlign: 'left',
    fontFamily: 'inherit',
    background: isDecision ? '#f5fdf8' : '#fff',
    border: selected ? '1.5px solid #04454c' : `1px solid ${isDecision ? '#a4f4cd' : '#e6e9eb'}`,
    borderRadius: 14,
    boxShadow: selected
      ? '0 0 0 4px rgba(101,236,172,0.32), 0 10px 24px rgba(4,69,76,0.12)'
      : '0 2px 6px rgba(4,69,76,0.06), 0 1px 2px rgba(4,69,76,0.04)',
    padding: '12px 14px 13px',
    transition: 'box-shadow 200ms cubic-bezier(0.2,0.7,0.2,1), border-color 200ms, transform 200ms',
    overflow: 'hidden',
  };
  if (!isDecision) {
    base.borderLeft = `4px solid ${role.bar}`;
  }
  return (
    <button
      ref={registerRef}
      type="button"
      style={base}
      onClick={(e) => { e.stopPropagation(); onClick(node.id); }}
      className="pm-node"
      data-node-id={node.id}
    >
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 7 }}>
        {isDecision ? (
          <span style={{ width: 15, height: 15, background: '#65ecac', transform: 'rotate(45deg)', borderRadius: 3, flexShrink: 0, display: 'inline-block' }} />
        ) : (
          <span style={{ width: 9, height: 9, borderRadius: 999, background: role.bar, flexShrink: 0 }} />
        )}
        <span style={{ fontSize: 10.5, fontWeight: 600, letterSpacing: '0.04em', textTransform: 'uppercase', color: isDecision ? '#1f9c69' : '#6b7273' }}>
          {isDecision ? 'Decision' : ROLE_TAG[node.role]}
        </span>
        {node.num != null && (
          <span style={{ marginLeft: 'auto', width: 20, height: 20, borderRadius: 999, background: '#04454c', color: '#65ecac', fontSize: 11, fontWeight: 700, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>{node.num}</span>
        )}
        {isMilestone && node.num == null && (
          <span style={{ marginLeft: 'auto', fontSize: 13, color: '#65ecac' }}>◆</span>
        )}
      </div>
      <div style={{ fontFamily: "'Poppins', sans-serif", fontSize: 14, fontWeight: 600, color: '#04454c', lineHeight: 1.22, letterSpacing: '-0.01em' }}>{node.title}</div>
      {node.sub && <div style={{ fontSize: 11.5, color: '#6b7273', lineHeight: 1.4, marginTop: 4 }}>{node.sub}</div>}
      {node.link && (
        <div style={{ marginTop: 9, fontSize: 11, fontWeight: 600, color: '#1f9c69', display: 'flex', alignItems: 'center', gap: 5 }}>
          Open the day-one map <span style={{ fontSize: 13 }}>→</span>
        </div>
      )}
      <span className="pm-expand" style={{ position: 'absolute', right: 11, bottom: 10, fontSize: 11, color: '#aaa', opacity: 0, transition: 'opacity 160ms' }}>expand ↗</span>
    </button>
  );
}

// ---- Connector overlay (handoff badge / branch label) ---------------------
function EdgeLabel({ mid, conn, roles }) {
  const left = mid.x;
  const top = mid.y;
  const wrap = { position: 'absolute', left, top, transform: 'translate(-50%, -50%)', zIndex: 4, pointerEvents: 'none' };
  if (conn.handoff) {
    const fromRole = roles[conn._fromRole];
    const toRole = roles[conn._toRole];
    return (
      <div style={wrap}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6, background: '#04454c', borderRadius: 999, padding: '4px 10px 4px 7px', boxShadow: '0 4px 12px rgba(4,69,76,0.22)', whiteSpace: 'nowrap' }}>
          <span style={{ display: 'flex', alignItems: 'center', gap: 3 }}>
            <span style={{ width: 8, height: 8, borderRadius: 999, background: fromRole.bar, outline: '1.5px solid rgba(255,255,255,0.5)' }} />
            <span style={{ color: '#65ecac', fontSize: 10 }}>→</span>
            <span style={{ width: 8, height: 8, borderRadius: 999, background: toRole.bar, outline: '1.5px solid rgba(255,255,255,0.5)' }} />
          </span>
          <span style={{ fontSize: 9.5, fontWeight: 700, letterSpacing: '0.07em', textTransform: 'uppercase', color: '#fff' }}>Handoff</span>
          {conn.label && <span style={{ fontSize: 10.5, fontWeight: 500, color: 'rgba(255,255,255,0.82)', borderLeft: '1px solid rgba(255,255,255,0.25)', paddingLeft: 7 }}>{conn.label}</span>}
        </div>
      </div>
    );
  }
  if (conn.label) {
    return (
      <div style={wrap}>
        <span style={{ background: '#fff', border: '1px solid #e6e9eb', borderRadius: 999, padding: '2px 9px', fontSize: 10.5, fontWeight: 600, color: '#04454c', whiteSpace: 'nowrap', boxShadow: '0 1px 2px rgba(4,69,76,0.06)' }}>{conn.label}</span>
      </div>
    );
  }
  return null;
}

// ---- Map canvas -----------------------------------------------------------
function ProcessMap({ view, roles, selectedId, onSelect }) {
  const nodeEls = React.useRef({});
  const [sizes, setSizes] = React.useState({});
  const nodeById = React.useMemo(() => {
    const m = {}; view.nodes.forEach((n) => { m[n.id] = n; }); return m;
  }, [view]);

  React.useLayoutEffect(() => {
    const s = {};
    view.nodes.forEach((n) => {
      const el = nodeEls.current[n.id];
      if (el) s[n.id] = el.offsetHeight;
    });
    setSizes(s);
  }, [view]);

  const rectOf = (n) => ({ x: n.x, y: n.y, w: n.w, h: sizes[n.id] || 76 });
  const ready = Object.keys(sizes).length >= view.nodes.length;

  const edges = ready ? view.connectors.map((c, i) => {
    const from = nodeById[c.from]; const to = nodeById[c.to];
    if (!from || !to) return null;
    const { d, mid } = buildPath(rectOf(from), rectOf(to), c.fromSide, c.toSide);
    return { key: i, d, mid, conn: { ...c, _fromRole: from.role, _toRole: to.role } };
  }).filter(Boolean) : [];

  return (
    <div style={{ position: 'relative', width: view.width, height: view.height }} onClick={() => onSelect(null)}>
      {/* swimlane bands */}
      {view.swimlanes && SUMMIT.LANE_ORDER.map((laneKey, idx) => {
        const role = roles[laneKey];
        const top = SUMMIT.LANE_TOP[laneKey];
        return (
          <div key={laneKey} style={{ position: 'absolute', left: 0, top, width: view.width, height: SUMMIT.LANE_H, background: idx % 2 === 0 ? '#fbfcfc' : '#f7f9fa', borderTop: '1px solid #eef1f2', borderBottom: idx === SUMMIT.LANE_ORDER.length - 1 ? '1px solid #eef1f2' : 'none', zIndex: 0 }}>
            <div style={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: 4, background: role.bar, opacity: 0.85 }} />
            <div style={{ position: 'absolute', left: 18, top: 14, maxWidth: 158 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 7 }}>
                <span style={{ width: 24, height: 24, borderRadius: 999, background: role.bar, color: laneKey === 'coord' ? '#04454c' : '#fff', fontSize: 9.5, fontWeight: 700, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>{role.initials}</span>
                <span style={{ fontFamily: "'Poppins', sans-serif", fontSize: 13, fontWeight: 700, color: '#04454c' }}>{role.name}</span>
              </div>
              <div style={{ fontSize: 10.5, color: '#6b7273', marginTop: 5, lineHeight: 1.3 }}>{role.title}</div>
            </div>
          </div>
        );
      })}

      {/* connectors */}
      <svg width={view.width} height={view.height} style={{ position: 'absolute', left: 0, top: 0, zIndex: 1, pointerEvents: 'none' }}>
        <defs>
          <marker id="pm-arrow" markerWidth="9" markerHeight="9" refX="6.5" refY="4" orient="auto" markerUnits="userSpaceOnUse">
            <path d="M1,1 L7,4 L1,7" fill="none" stroke="#04454c" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
          </marker>
          <marker id="pm-arrow-dash" markerWidth="9" markerHeight="9" refX="6.5" refY="4" orient="auto" markerUnits="userSpaceOnUse">
            <path d="M1,1 L7,4 L1,7" fill="none" stroke="#1f9c69" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
          </marker>
        </defs>
        {edges.map((e) => (
          <path
            key={e.key}
            d={e.d}
            fill="none"
            stroke={e.conn.dashed ? '#1f9c69' : '#a9b6b8'}
            strokeWidth={e.conn.handoff ? 2 : 1.6}
            strokeDasharray={e.conn.dashed ? '5 5' : 'none'}
            strokeLinecap="round"
            strokeLinejoin="round"
            markerEnd={e.conn.dashed ? 'url(#pm-arrow-dash)' : 'url(#pm-arrow)'}
            opacity={selectedId && selectedId !== e.conn.from && selectedId !== e.conn.to ? 0.35 : 1}
            style={{ transition: 'opacity 200ms' }}
          />
        ))}
      </svg>

      {/* edge labels + handoff badges */}
      {edges.map((e) => (
        <EdgeLabel key={`l${e.key}`} mid={e.mid} conn={e.conn} roles={roles} />
      ))}

      {/* nodes */}
      {view.nodes.map((n) => (
        <NodeCard
          key={n.id}
          node={n}
          role={roles[n.role]}
          selected={selectedId === n.id}
          onClick={onSelect}
          registerRef={(el) => { nodeEls.current[n.id] = el; }}
        />
      ))}
    </div>
  );
}

window.ProcessMap = ProcessMap;
window.ROLE_TAG = ROLE_TAG;
