// EcosystemMap — animated SVG venture map.
// Nodes drift on slow Lissajous paths, lines re-anchor every frame,
// the live connection carries a flowing dash + travelling pulse,
// nodes magnetize gently toward the cursor, hover shows a tooltip,
// clicking the live node opens the venture drawer.
const ECO_CX = 600, ECO_CY = 360, ECO_VW = 1200, ECO_VH = 720, ECO_CR = 80;

const ECO_NODES = [
  { id: 'bridge', name: 'Bridge Web Design', lines: ['Bridge', 'Web Design'], tag: '01 — operating', kind: 'live', angle: -32, dist: 295, r: 58 },
  { id: 'n02', name: 'Venture 02', lines: ['02'], tag: 'in build', kind: 'build', angle: 142, dist: 295, r: 42 },
  { id: 'n03', name: 'Venture 03', lines: ['03'], tag: 'reserved', kind: 'res', angle: 58, dist: 330, r: 30 },
  { id: 'n04', name: 'Venture 04', lines: ['04'], tag: 'reserved', kind: 'res', angle: -148, dist: 295, r: 26 },
  { id: 'n05', name: 'Venture 05', lines: ['05'], tag: 'reserved', kind: 'res', angle: 99, dist: 350, r: 23 },
];

function ecoBase(n) {
  const a = (n.angle * Math.PI) / 180;
  return { x: ECO_CX + Math.cos(a) * n.dist, y: ECO_CY + Math.sin(a) * n.dist * 0.78 };
}

function EcoVMark({ scale = 1 }) {
  return (
    <g transform={`scale(${scale})`}>
      <rect x="-16" y="-21" width="9" height="42" rx="5" fill="var(--linen)" transform="rotate(-15 -16 -21)"></rect>
      <rect x="7" y="-21" width="9" height="42" rx="5" fill="var(--accent)" transform="rotate(15 16 -21)"></rect>
    </g>
  );
}

function EcosystemMap({ motion, onOpen }) {
  const { t } = useI18n();
  const tagFor = (n) => t.eco.nodeTags[n.kind];
  const svgRef = React.useRef(null);
  const stageRef = React.useRef(null);
  const tipRef = React.useRef(null);
  const nodeRefs = React.useRef({});
  const lineRefs = React.useRef({});
  const pulseRef = React.useRef(null);
  const centerRef = React.useRef(null);
  const mouse = React.useRef(null);
  const hoverId = React.useRef(null);
  const [tip, setTip] = React.useState(null);
  // On phones the full 1200x720 map shrinks to nothing — crop into the cluster
  // (a tighter, taller viewBox) so the nodes are big and tappable.
  const [viewBox, setViewBox] = React.useState('0 0 1200 720');
  React.useEffect(() => {
    const calc = () => setViewBox(window.innerWidth < 760 ? '300 110 600 500' : '0 0 1200 720');
    calc();
    window.addEventListener('resize', calc);
    return () => window.removeEventListener('resize', calc);
  }, []);

  const speed = motion === 'still' ? 0 : motion === 'lively' ? 1.8 : 1;

  React.useEffect(() => {
    const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    const state = {};
    ECO_NODES.forEach((n, i) => {
      const b = ecoBase(n);
      state[n.id] = { x: b.x, y: b.y, bx: b.x, by: b.y, s: 1, i };
    });
    const cState = { x: ECO_CX, y: ECO_CY };
    let raf, last = performance.now(), t = Math.random() * 100;

    const frame = (now) => {
      const dt = Math.min(0.05, (now - last) / 1000);
      last = now;
      if (!reduced) t += dt * speed;

      ECO_NODES.forEach((n) => {
        const s = state[n.id];
        const amp = n.kind === 'live' ? 10 : 13;
        let tx = s.bx + Math.sin(t * 0.5 + s.i * 1.9) * amp * (speed || 0);
        let ty = s.by + Math.cos(t * 0.36 + s.i * 2.6) * amp * 0.8 * (speed || 0);
        // cursor magnetism
        if (mouse.current) {
          const dx = mouse.current.x - s.x, dy = mouse.current.y - s.y;
          const d = Math.hypot(dx, dy);
          if (d < 180 && d > 0.001) {
            const pull = (1 - d / 180) * 26;
            tx += (dx / d) * pull;
            ty += (dy / d) * pull;
          }
        }
        s.x += (tx - s.x) * 0.07;
        s.y += (ty - s.y) * 0.07;
        const targetScale = hoverId.current === n.id ? 1.09 : 1;
        s.s += (targetScale - s.s) * 0.14;

        const g = nodeRefs.current[n.id];
        if (g) g.setAttribute('transform', `translate(${s.x} ${s.y}) scale(${s.s})`);

        // line: center edge -> node edge
        const ln = lineRefs.current[n.id];
        if (ln) {
          const vx = s.x - cState.x, vy = s.y - cState.y;
          const d = Math.hypot(vx, vy) || 1;
          const ux = vx / d, uy = vy / d;
          ln.setAttribute('x1', cState.x + ux * ECO_CR);
          ln.setAttribute('y1', cState.y + uy * ECO_CR);
          ln.setAttribute('x2', s.x - ux * (n.r + 3));
          ln.setAttribute('y2', s.y - uy * (n.r + 3));
          if (n.kind === 'live') {
            ln.setAttribute('stroke-dashoffset', String(-t * 34));
            // travelling pulse
            const p = pulseRef.current;
            if (p) {
              const u = speed ? (t * 0.22) % 1 : 0.55;
              const x1 = cState.x + ux * ECO_CR, y1 = cState.y + uy * ECO_CR;
              const x2 = s.x - ux * (n.r + 3), y2 = s.y - uy * (n.r + 3);
              p.setAttribute('cx', String(x1 + (x2 - x1) * u));
              p.setAttribute('cy', String(y1 + (y2 - y1) * u));
            }
          }
        }
      });

      // center breathes very slightly
      const cg = centerRef.current;
      if (cg) {
        const cx = ECO_CX + Math.sin(t * 0.3) * 4 * (speed || 0);
        const cy = ECO_CY + Math.cos(t * 0.22) * 3 * (speed || 0);
        cState.x = cx; cState.y = cy;
        cg.setAttribute('transform', `translate(${cx} ${cy})`);
      }

      // tooltip follows hovered node
      if (hoverId.current && tipRef.current && stageRef.current) {
        const s = state[hoverId.current];
        tipRef.current.style.left = (s.x / ECO_VW) * 100 + '%';
        tipRef.current.style.top = ((s.y - ECO_NODES.find((n) => n.id === hoverId.current).r) / ECO_VH) * 100 + '%';
      }

      raf = requestAnimationFrame(frame);
    };
    raf = requestAnimationFrame(frame);
    return () => cancelAnimationFrame(raf);
  }, [speed]);

  const toSvg = (e) => {
    const r = svgRef.current.getBoundingClientRect();
    return { x: ((e.clientX - r.left) / r.width) * ECO_VW, y: ((e.clientY - r.top) / r.height) * ECO_VH };
  };

  const enter = (n) => { hoverId.current = n.id; setTip(n); };
  const leave = () => { hoverId.current = null; setTip(null); };

  return (
    <div className="eco-stage" ref={stageRef}>
      <svg ref={svgRef} viewBox={viewBox}
        onMouseMove={(e) => { mouse.current = toSvg(e); }}
        onMouseLeave={() => { mouse.current = null; }}>

        {/* faint orbit rings */}
        <g fill="none" stroke="rgba(250,255,250,0.06)" strokeDasharray="2 8">
          <circle cx={ECO_CX} cy={ECO_CY} r="185"></circle>
          <circle cx={ECO_CX} cy={ECO_CY} r="265"></circle>
        </g>

        {/* connections */}
        {ECO_NODES.map((n) => (
          <line key={'l' + n.id}
            ref={(el) => { lineRefs.current[n.id] = el; }}
            stroke={n.kind === 'live' ? 'var(--accent)' : 'rgba(250,255,250,0.16)'}
            strokeWidth={n.kind === 'live' ? 1.6 : 1}
            strokeDasharray={n.kind === 'live' ? '4 8' : n.kind === 'build' ? '3 6' : '2 7'}
            opacity={n.kind === 'res' ? 0.55 : 0.9}></line>
        ))}
        <circle ref={pulseRef} r="3.4" fill="var(--accent)"></circle>

        {/* center node */}
        <g ref={centerRef} transform={`translate(${ECO_CX} ${ECO_CY})`}>
          <circle r={ECO_CR} fill="#11160f" stroke="rgba(250,255,250,0.28)" strokeWidth="1.4"></circle>
          <circle r={ECO_CR + 10} fill="none" stroke="rgba(43,238,75,0.18)" strokeWidth="1"></circle>
          <g transform="translate(0 -16)"><EcoVMark scale={0.85} /></g>
          <text className="eco-label" y="44" textAnchor="middle" fontSize="22" letterSpacing="-0.03em">
            ves<tspan fill="var(--accent)">ka</tspan>
          </text>
        </g>

        {/* venture nodes */}
        {ECO_NODES.map((n) => {
          const stroke = n.kind === 'live' ? 'var(--accent)' : n.kind === 'build' ? 'rgba(250,255,250,0.5)' : 'rgba(250,255,250,0.28)';
          const dash = n.kind === 'live' ? 'none' : n.kind === 'build' ? '5 5' : '3 6';
          const op = n.kind === 'res' ? 0.6 : 1;
          return (
            <g key={n.id} className={'eco-node ' + n.kind} opacity={op}
              ref={(el) => { nodeRefs.current[n.id] = el; }}
              onMouseEnter={() => enter(n)}
              onMouseLeave={leave}
              onClick={n.kind === 'live' ? () => onOpen(n) : undefined}>
              <circle r={n.r} fill={n.kind === 'live' ? '#101610' : 'transparent'}
                stroke={stroke} strokeWidth={n.kind === 'live' ? 1.6 : 1.2}
                strokeDasharray={dash}></circle>
              {n.kind === 'live' && <circle r={n.r + 7} fill="none" stroke="rgba(43,238,75,0.22)" strokeWidth="1"></circle>}
              {n.lines.map((ln2, i) => (
                <text key={i} className="eco-label" textAnchor="middle"
                  fontSize={n.kind === 'live' ? 15 : 15}
                  opacity={n.kind === 'res' ? 0.75 : 1}
                  y={(i - (n.lines.length - 1) / 2) * 17 + 1}>{ln2}</text>
              ))}
              <text className="eco-tag" textAnchor="middle" fontSize="9.5" y={n.r + 18}>{tagFor(n)}</text>
            </g>
          );
        })}
      </svg>

      <div className="eco-legend">
        <span className="tag"><span className="dot">●</span> {t.eco.legendLive}</span>
        <span className="tag">◌ {t.eco.legendBuild}</span>
        <span className="tag" style={{ opacity: 0.6 }}>· {t.eco.legendRes}</span>
      </div>

      <div ref={tipRef} className={'eco-tip' + (tip ? ' on' : '')}>
        {tip && (
          <React.Fragment>
            <span className="name">{t.eco.nodeNames[tip.id]}</span>
            <span className="tag">{tip.kind === 'live' ? t.eco.clickToOpen : tagFor(tip)}</span>
          </React.Fragment>
        )}
      </div>
    </div>
  );
}

Object.assign(window, { EcosystemMap });
