import { beforeAll, describe, expect, it } from "vitest"
import { parser } from "@lezer/markdown"
import { GFM } from "@lezer/markdown"
import { createComarkExtensions } from "./index"

let fullParser: ReturnType<typeof parser.configure>

beforeAll(() => {
  fullParser = parser.configure([GFM, ...createComarkExtensions()])
})

function parse(text: string) {
  const tree = fullParser.parse(text)
  const nodes: { name: string; from: number; to: number }[] = []
  tree.iterate({
    enter: (node) => {
      nodes.push({
        name: node.type.name,
        from: node.from,
        to: node.to,
      })
    },
  })
  return nodes
}

function nodeNames(text: string): string[] {
  return parse(text).map((n) => n.name)
}

describe("Span attributes", () => {
  it("parses span with class", () => {
    const names = nodeNames("[text]{.highlight}")
    expect(names).toContain("Span")
    expect(names).toContain("SpanBody")
    expect(names).toContain("SpanAttrs")
  })

  it("parses span with id", () => {
    const names = nodeNames("[text]{#my-id}")
    expect(names).toContain("Span")
  })

  it("parses span with key-value", () => {
    const names = nodeNames("[text]{data-value=\"test\"}")
    expect(names).toContain("Span")
  })

  it("parses span with multiple attrs", () => {
    const names = nodeNames("[text]{.highlight #my-id key=\"val\"}")
    expect(names).toContain("Span")
    expect(names).toContain("SpanAttrs")
  })

  it("sits within a paragraph", () => {
    const names = nodeNames("This is [highlighted]{.yellow} text.")
    expect(names).toContain("Span")
    expect(names).toContain("SpanBody")
    expect(names).toContain("SpanAttrs")
  })

  it("does not match when space before braces", () => {
    // space between ] and { means block-level attribute, not span
    const names = nodeNames("[text] {.class}")
    expect(names).not.toContain("Span")
  })

  it("extracts body text", () => {
    const nodes = parse("[Important]{.badge}")
    const bodyNode = nodes.find((n) => n.name === "SpanBody")
    expect(bodyNode).toBeDefined()
    expect("[Important]{.badge}".slice(bodyNode!.from, bodyNode!.to)).toBe("Important")
  })
})
