import { GapCursor } from "prosemirror-gapcursor"
import { Selection, TextSelection } from "prosemirror-state"
import type { EditorView } from "prosemirror-view"
import type { FocusPosition } from "./useFocusRegistry"

function setSafeSelection(view: EditorView, pos: number) {
  const doc = view.state.doc
  const resolved = doc.resolve(Math.max(1, Math.min(pos, doc.content.size)))
  view.dispatch(view.state.tr.setSelection(Selection.near(resolved)))
}

export function focusAt(view: EditorView | null, cursorPosition?: FocusPosition) {
  if (!view) return
  const doc = view.state.doc

  if (
    cursorPosition &&
    typeof cursorPosition === "object" &&
    "left" in cursorPosition
  ) {
    view.focus()
    requestAnimationFrame(() => {
      const rect = view.dom.getBoundingClientRect()
      const targetY =
        cursorPosition.edge === "top" ? rect.top + 5 : rect.bottom - 5
      const pos = view.posAtCoords({ left: cursorPosition.left, top: targetY })
      if (pos) setSafeSelection(view, pos.pos)
      else setSafeSelection(view, cursorPosition.edge === "top" ? 1 : Math.max(1, doc.content.size - 1))
    })
    return
  }

  if (cursorPosition === "start") {
    if (doc.content.size > 0) setSafeSelection(view, 1)
    view.focus()
    return
  }

  if (cursorPosition === "end") {
    if (doc.content.size > 1) setSafeSelection(view, doc.content.size - 1)
    view.focus()
    return
  }

  if (typeof cursorPosition === "number") {
    if (doc.content.size > 1) {
      const pos = Math.max(1, Math.min(cursorPosition, doc.content.size - 1))
      setSafeSelection(view, pos)
    }
    view.focus()
    return
  }

  view.focus()
}

export function isValidGapCursor($pos: unknown): boolean {
  return (GapCursor as any).valid($pos)
}
