// Click-to-toggle zoom + drag-to-pan when zoomed + wheel-to-zoom.
// Returns reactive state + handlers a component can spread onto its
// root element.

import { reactive } from 'vue'

const MIN_SCALE = 1
const MAX_SCALE = 4
const WHEEL_SENSITIVITY = 0.0015

export function usePanZoom() {
  const state = reactive({
    scale: 1,
    x: 0,
    y: 0,
    panning: false
  })

  let dragOriginX = 0
  let dragOriginY = 0
  let panOriginX = 0
  let panOriginY = 0

  function reset() {
    state.scale = 1
    state.x = 0
    state.y = 0
  }

  function toggleZoom(ev) {
    if (state.scale > 1) { reset(); return }
    state.scale = 2
    // Zoom centered on click point
    if (ev && ev.currentTarget) {
      const rect = ev.currentTarget.getBoundingClientRect()
      const cx = ev.clientX - rect.left - rect.width / 2
      const cy = ev.clientY - rect.top - rect.height / 2
      state.x = -cx
      state.y = -cy
    }
  }

  function onWheel(ev) {
    ev.preventDefault()
    const delta = -ev.deltaY * WHEEL_SENSITIVITY
    const next = Math.min(MAX_SCALE, Math.max(MIN_SCALE, state.scale + delta * state.scale))
    state.scale = next
    if (next === MIN_SCALE) { state.x = 0; state.y = 0 }
  }

  function onPointerDown(ev) {
    if (state.scale === 1) return
    state.panning = true
    dragOriginX = ev.clientX
    dragOriginY = ev.clientY
    panOriginX = state.x
    panOriginY = state.y
    ev.currentTarget.setPointerCapture(ev.pointerId)
  }
  function onPointerMove(ev) {
    if (!state.panning) return
    state.x = panOriginX + (ev.clientX - dragOriginX)
    state.y = panOriginY + (ev.clientY - dragOriginY)
  }
  function onPointerUp(ev) {
    state.panning = false
    try { ev.currentTarget.releasePointerCapture(ev.pointerId) } catch {}
  }

  return {
    state,
    handlers: {
      onWheel,
      onPointerDown,
      onPointerMove,
      onPointerUp,
      onClick: toggleZoom
    },
    reset
  }
}
