// Card / arrow annotation — a draggable dark box connected to its anchor by a
// dashed line. PC-only feature.
//
// Data shape (one of):
//   { id, nodeId,        text, offset:{dx,dy} }   ← attached to a node
//   { id, targetEdgeId,  text, offset:{dx,dy} }   ← attached to an edge midpoint
//
// Canvas resolves the anchor (x,y) up-front and passes it in via `anchor`, so
// the components below don't care about node-vs-edge attachment.

const DEFAULT_OFFSET = { dx: 120, dy: 80 };

function NoteBox({ note, anchor, selected, onSelect, onDrag, onDragEnd, worldZoom }){
  if (!anchor) return null;
  const off = note.offset || DEFAULT_OFFSET;
  const x = anchor.x + (off.dx ?? DEFAULT_OFFSET.dx);
  const y = anchor.y + (off.dy ?? DEFAULT_OFFSET.dy);
  const moveState = React.useRef(null);
  const [dragging, setDragging] = React.useState(false);

  const onPointerDown = (e) => {
    e.stopPropagation();
    onSelect(note.id);
    const ox = off.dx ?? DEFAULT_OFFSET.dx;
    const oy = off.dy ?? DEFAULT_OFFSET.dy;
    moveState.current = { startX: e.clientX, startY: e.clientY, ox, oy, moved: false };
    try { e.currentTarget.setPointerCapture(e.pointerId); } catch(_){}
  };
  const onPointerMove = (e) => {
    if (!moveState.current) return;
    const { startX, startY, ox, oy } = moveState.current;
    const dx = (e.clientX - startX) / worldZoom;
    const dy = (e.clientY - startY) / worldZoom;
    if (Math.abs(dx)+Math.abs(dy) > 2) {
      moveState.current.moved = true;
      if (!dragging) setDragging(true);
    }
    onDrag(note.id, { dx: ox + dx, dy: oy + dy });
  };
  const onPointerUp = (e) => {
    if (!moveState.current) return;
    const moved = moveState.current.moved;
    moveState.current = null;
    setDragging(false);
    onDragEnd(note.id, moved);
    try { e.currentTarget.releasePointerCapture(e.pointerId); } catch(_){}
  };

  return (
    <div
      className={`note-box${selected?' selected':''}${dragging?' dragging':''}`}
      style={{ left:x, top:y }}
      onPointerDown={onPointerDown}
      onPointerMove={onPointerMove}
      onPointerUp={onPointerUp}
      onPointerCancel={onPointerUp}
    >
      <div className="note-body">{note.text || '解説を入力…'}</div>
    </div>
  );
}

// Dashed connector line from the anchor (node center or edge midpoint) to the
// note center. Rendered inside an SVG layer that scales with the world.
function NoteConnector({ note, anchor }){
  if (!anchor) return null;
  const off = note.offset || DEFAULT_OFFSET;
  const x = anchor.x + (off.dx ?? DEFAULT_OFFSET.dx);
  const y = anchor.y + (off.dy ?? DEFAULT_OFFSET.dy);
  return (
    <line
      className="note-connector"
      x1={anchor.x} y1={anchor.y}
      x2={x} y2={y}
    />
  );
}

window.NoteBox = NoteBox;
window.NoteConnector = NoteConnector;
window.DEFAULT_NOTE_OFFSET = DEFAULT_OFFSET;
