// 3D pointer dispatch. Registers the host touch callbacks lazily (first listener) and routes hits to
// the struck Node and to the active scene's listeners. Ported from worker/src/TouchEventSystem.ts.

import { ClickEvent, TouchStartEvent, type TrackHandler } from "../runtime/touch"
import { nodeRegistry } from "./Node"
import { glState } from "./state"

// Hits inside a loaded model (GLB) land on sub-entities the user never created a Node for — walk up
// the transform hierarchy to the nearest entity someone actually holds (the model's Node).
const resolveHitNode = (entityId: number) => {
  let node = nodeRegistry.get(entityId)
  for (let id = entityId, i = 0; !node && i < 32; i++) {
    id = _creator.getParent(id)
    if (id === 0) break
    node = nodeRegistry.get(id)
  }
  return node ?? null
}

const onTouchEnd = (pointerId: number, clientX: number, clientY: number, entityId: number): TrackHandler | null => {
  const scene = glState.activeScene
  if (!scene) return null
  const ev = new ClickEvent<any>(clientX, clientY, pointerId)
  if (entityId > 0) {
    const node = resolveHitNode(entityId)
    ev.target = node
    if (node) node._dispatchEvent("click", ev)
  } else {
    ev.target = null
  }
  for (const listener of scene._clickListeners.slice()) listener(ev)
  return null
}

const onTouchStart = (pointerId: number, clientX: number, clientY: number, entityId: number): TrackHandler | null => {
  const scene = glState.activeScene
  if (!scene) return null
  const ev = new TouchStartEvent<any>(clientX, clientY, pointerId)
  if (entityId > 0) {
    const node = resolveHitNode(entityId)
    ev.target = node
    if (node) {
      node._dispatchEvent("touchstart", ev)
      if (ev._trackHandler) return ev._trackHandler
    }
  } else {
    ev.target = null
  }
  for (const listener of scene._touchStartListeners.slice()) {
    listener(ev)
    if (ev._trackHandler) return ev._trackHandler
  }
  return null
}

let touchStartRegistered = false
export const registerTouchStartEvent = (): void => {
  if (touchStartRegistered) return
  touchStartRegistered = true
  _creatorUI.registerTouchStartEvent(onTouchStart)
}

let touchEndRegistered = false
export const registerTouchEndEvent = (): void => {
  if (touchEndRegistered) return
  touchEndRegistered = true
  _creatorUI.registerTouchEndEvent(onTouchEnd)
}
