/**
 * Während eines Drags automatischen Bildlauf auslösen (Viewport + scrollbare Bereiche unter dem Cursor).
 * @param {DragEvent} e
 * @param {{ edgePx?: number, scrollStep?: number }} [opts]
 */
export function autoScrollForDragNearEdges(e, opts = {}) {
  const edge = opts.edgePx ?? 80
  const step = opts.scrollStep ?? Math.max(24, Math.round(window.innerHeight * 0.05))
  const { clientX, clientY } = e

  const vh = window.innerHeight || 0
  const vw = window.innerWidth || 0

  let sy =
    clientY < edge ? -step : vh > 0 && clientY > vh - edge ? step : 0
  let sx =
    clientX < edge ? -step : vw > 0 && clientX > vw - edge ? step : 0

  if (sy !== 0) window.scrollBy(0, sy)
  if (sx !== 0) window.scrollBy(sx, 0)

  /** @type {HTMLElement|null} */
  let top = /** @type {HTMLElement|null} */ (document.elementFromPoint(clientX, clientY))

  /** @type {Set<HTMLElement>} */
  const done = new Set()

  /** @type {HTMLElement|null} */
  let walk = top
  const innerEdge = Math.min(edge, 40)

  while (walk && walk !== document.body) {
    if (!(walk instanceof HTMLElement)) break

    const cs = window.getComputedStyle(walk)
    const canY =
      walk.scrollHeight - walk.clientHeight > 6 &&
      (cs.overflowY === 'auto' || cs.overflowY === 'scroll')
    const canX =
      walk.scrollWidth - walk.clientWidth > 6 &&
      (cs.overflowX === 'auto' || cs.overflowX === 'scroll')

    if ((canY || canX) && !done.has(walk)) {
      done.add(walk)
      const rect = walk.getBoundingClientRect()

      const relY = clientY - rect.top
      const relX = clientX - rect.left

      if (canY) {
        if (relY < innerEdge && walk.scrollTop > 0) walk.scrollTop -= step
        else if (rect.height - relY < innerEdge && walk.scrollTop < walk.scrollHeight - walk.clientHeight) {
          walk.scrollTop += step
        }
      }
      if (canX) {
        if (relX < innerEdge && walk.scrollLeft > 0) walk.scrollLeft -= step
        else if (rect.width - relX < innerEdge && walk.scrollLeft < walk.scrollWidth - walk.clientWidth) {
          walk.scrollLeft += step
        }
      }
    }

    walk = walk.parentElement
  }
}
