import { TextSelection } from "prosemirror-state"
import type { EditorView } from "prosemirror-view"
import { vi } from "vitest"
import { contentToDoc } from "@/lib/content-model"
import { schema } from "@/lib/schema"

/**
 * Deterministic sequential ID generator for tests.
 * Usage: `const ids = stableId("block")` → `ids()` → `"block-0"`, `"block-1"`, ...
 */
export function stableId(prefix: string): () => string {
  let n = 0
  return () => `${prefix}-${n++}`
}

/**
 * Create a minimal KeyboardEvent-like object for testing keyboard handlers.
 */
export function createMockKeyEvent(
  key: string,
  modifiers: Record<string, boolean> = {},
): KeyboardEvent {
  return {
    key,
    altKey: modifiers.alt ?? false,
    ctrlKey: modifiers.ctrl ?? false,
    metaKey: modifiers.meta ?? false,
    shiftKey: modifiers.shift ?? modifiers.shiftKey ?? false,
  } as KeyboardEvent
}

/**
 * Create a mock EditorView with a document from plain text content.
 * Only suitable for testing keyboard handlers that inspect
 * state.doc, state.selection, coordsAtPos, dispatch, and endOfTextblock.
 */
export function createMockView(content: string, cursorPos: number) {
  const doc = contentToDoc(content)
  const selection = TextSelection.create(doc, cursorPos)

  const endOfTextblock = (dir: string) => {
    if (dir === "up") return cursorPos <= 1
    if (dir === "down") return cursorPos >= doc.content.size - 2
    return false
  }

  return {
    state: { doc, selection },
    coordsAtPos: () => ({ left: 100, top: 200 }),
    dispatch: vi.fn(),
    endOfTextblock,
  } as unknown as EditorView
}

/**
 * Create a ProseMirror doc node with a single paragraph containing text.
 */
export function makeParaDoc(content: string) {
  const textNode = content.length > 0 ? schema.text(content) : undefined
  const para = textNode
    ? schema.node("paragraph", {}, [textNode])
    : schema.node("paragraph")
  return schema.node("doc", {}, [para])
}
