import { TextSelection } from "prosemirror-state"
import { describe, expect, it, vi } from "vitest"
import { contentToDoc } from "@/lib/content-model"

describe("focusAt logic", () => {
  // Test the focusAt function behavior directly
  function focusAt(
    doc: ReturnType<typeof contentToDoc>,
    view: {
      dispatch: (tr: { selection: { head: number } }) => void
      focus: () => void
    } | null,
    cursorPosition?: "start" | "end" | number,
  ) {
    if (!view) return
    const docObj = typeof doc === "string" ? contentToDoc(doc) : doc

    let pos: number
    if (cursorPosition === "start") {
      pos = 1
    } else if (cursorPosition === "end") {
      pos = docObj.content.size - 1
    } else if (typeof cursorPosition === "number") {
      pos = Math.max(1, Math.min(cursorPosition, docObj.content.size - 1))
    } else {
      view.focus()
      return
    }

    try {
      view.dispatch({ selection: TextSelection.create(docObj, pos) })
      view.focus()
    } catch {
      view.focus()
    }
  }

  it("calculates start position correctly", () => {
    const doc = contentToDoc("hello")
    const dispatch = vi.fn()
    const focus = vi.fn()

    focusAt(doc, { dispatch, focus }, "start")

    expect(dispatch).toHaveBeenCalled()
    const call = dispatch.mock.calls[0][0]
    expect(call.selection.anchor).toBe(1)
    expect(focus).toHaveBeenCalled()
  })

  it("calculates end position correctly", () => {
    const doc = contentToDoc("hello")
    const dispatch = vi.fn()
    const focus = vi.fn()

    focusAt(doc, { dispatch, focus }, "end")

    expect(dispatch).toHaveBeenCalled()
    const call = dispatch.mock.calls[0][0]
    expect(call.selection.anchor).toBe(doc.content.size - 1)
    expect(focus).toHaveBeenCalled()
  })

  it("clamps number position to valid range", () => {
    const doc = contentToDoc("hi")
    const dispatch = vi.fn()
    const focus = vi.fn()

    // Position 1000 should clamp to end
    focusAt(doc, { dispatch, focus }, 1000)

    const call = dispatch.mock.calls[0][0]
    expect(call.selection.anchor).toBe(doc.content.size - 1)
  })

  it("focuses without selection when no position given", () => {
    const doc = contentToDoc("hello")
    const dispatch = vi.fn()
    const focus = vi.fn()

    focusAt(doc, { dispatch, focus }, undefined)

    expect(dispatch).not.toHaveBeenCalled()
    expect(focus).toHaveBeenCalled()
  })

  it("clamps position below 1 to 1", () => {
    const doc = contentToDoc("hello")
    const dispatch = vi.fn()
    const focus = vi.fn()

    focusAt(doc, { dispatch, focus }, -5)

    const call = dispatch.mock.calls[0][0]
    expect(call.selection.anchor).toBe(1)
  })

  it("handles empty document for position calculation", () => {
    const doc = contentToDoc("")
    const dispatch = vi.fn()
    const focus = vi.fn()

    // Empty doc has size 2 (doc wrapper + empty paragraph)
    // end position should be 1
    focusAt(doc, { dispatch, focus }, "end")

    expect(dispatch).toHaveBeenCalled()
    const call = dispatch.mock.calls[0][0]
    expect(call.selection.anchor).toBe(1)
  })

  it("handles null view gracefully", () => {
    // Should not throw
    focusAt(contentToDoc("test"), null, "start")
  })

  it("handles specific valid position", () => {
    const doc = contentToDoc("hello world")
    const dispatch = vi.fn()
    const focus = vi.fn()

    focusAt(doc, { dispatch, focus }, 5)

    const call = dispatch.mock.calls[0][0]
    expect(call.selection.anchor).toBe(5)
  })

  it("handles multiline document end position", () => {
    const doc = contentToDoc("line1\nline2\nline3")
    const dispatch = vi.fn()
    const focus = vi.fn()

    focusAt(doc, { dispatch, focus }, "end")

    expect(dispatch).toHaveBeenCalled()
    expect(focus).toHaveBeenCalled()
  })
})
