import { EditorState, TextSelection } from "prosemirror-state"
import { EditorView } from "prosemirror-view"
import { bench, describe } from "vitest"
import {
  insertBlockRef,
  insertPageRef,
  insertTag,
  isFormatActive,
} from "@/lib/formatting"
import { MarkdownRuleEngine, parseMarkdown } from "@/lib/markdown-parser"
import { schema } from "@/lib/schema"

const engine = new MarkdownRuleEngine()

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])
}

const BENCH_DOM = document.createElement("div")

const DOCUMENTS = {
  plain: "hello world",
  bold: "this is **bold** and **more bold** text",
  mixed:
    "**bold** *italic* `code` ~~strike~~ ^^highlight^^ and [[Page Ref]] ((block-id)) #tag",
  heading:
    "# Title\n\n## Section\n\n### Subsection\n\nTODO task here\n\n> [!NOTE] A note",
  kitchenSink: [
    "# Documentation\n\n",
    "This is a **paragraph** with *multiple* `inline` ~~styles~~.\n\n",
    "## Features\n\n",
    "> [!TIP] Use callouts for **important** notes\n\n",
    "TODO Add [[Page Reference]] and ((block-123)) support\n\n",
    "priority:: high\nauthor:: John\n",
  ].join(""),
}

describe("MarkdownRuleEngine.parse", () => {
  bench("plain text", () => {
    parseMarkdown(DOCUMENTS.plain, engine)
  })

  bench("bold text", () => {
    parseMarkdown(DOCUMENTS.bold, engine)
  })

  bench("mixed inline tokens", () => {
    parseMarkdown(DOCUMENTS.mixed, engine)
  })

  bench("block tokens (headings, tasks, callouts)", () => {
    parseMarkdown(DOCUMENTS.heading, engine)
  })

  bench("kitchen sink (all syntax)", () => {
    parseMarkdown(DOCUMENTS.kitchenSink, engine)
  })
})

describe("isFormatActive", () => {
  let view: EditorView

  const boldContent = "this is **bold** text"
  const dom = document.createElement("div")

  bench("bold content at cursor inside bold", () => {
    if (!view) {
      const docText = schema.text(boldContent)
      const para = schema.node("paragraph", {}, [docText])
      const doc = schema.node("doc", {}, [para])
      const state = EditorState.create({
        doc,
        schema,
        selection: TextSelection.create(doc, 13, 13),
      })
      view = new EditorView(dom, { state })
    }
    isFormatActive(view, "bold")
  })

  bench("bold content at cursor outside bold", () => {
    isFormatActive(view, "italic")
  })

  bench("mixed document at cursor inside bold", () => {
    isFormatActive(view, "bold")
  })
})

describe("insertPageRef", () => {
  bench("insert [[Page]] at cursor end", () => {
    const doc = makeParaDoc("hello ")
    const state = EditorState.create({
      doc,
      schema,
      selection: TextSelection.create(doc, 7, 7),
    })
    const view = new EditorView(BENCH_DOM, { state })
    insertPageRef(view, "Page")
    view.destroy()
  })
})

describe("insertBlockRef", () => {
  bench("insert ((block-id)) at cursor end", () => {
    const doc = makeParaDoc("hello ")
    const state = EditorState.create({
      doc,
      schema,
      selection: TextSelection.create(doc, 7, 7),
    })
    const view = new EditorView(BENCH_DOM, { state })
    insertBlockRef(view, "abc123")
    view.destroy()
  })
})

describe("insertTag", () => {
  bench("insert #tag at cursor end", () => {
    const doc = makeParaDoc("hello ")
    const state = EditorState.create({
      doc,
      schema,
      selection: TextSelection.create(doc, 7, 7),
    })
    const view = new EditorView(BENCH_DOM, { state })
    insertTag(view, "bug")
    view.destroy()
  })
})
