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("BlockComponent", () => {
  it("parses a simple block component", () => {
    const names = nodeNames("::query{type=\"TODO\"}\nResults\n::")
    expect(names).toContain("BlockComponent")
    expect(names).toContain("ComponentName")
    expect(names).toContain("ComponentAttrs")
    expect(names).toContain("ComponentBody")
  })

  it("extracts component name", () => {
    const nodes = parse("::note{title=\"Info\"}\nContent\n::")
    const nameNode = nodes.find((n) => n.name === "ComponentName")
    expect(nameNode).toBeDefined()
    expect("::note{title=\"Info\"}\nContent\n::".slice(nameNode!.from, nameNode!.to)).toBe("note")
  })

  it("extracts attrs", () => {
    const nodes = parse("::alert{type=\"warning\"}\nBe careful\n::")
    const attrsNode = nodes.find((n) => n.name === "ComponentAttrs")
    expect(attrsNode).toBeDefined()
    expect("::alert{type=\"warning\"}\nBe careful\n::".slice(attrsNode!.from, attrsNode!.to)).toBe('{type="warning"}')
  })

  it("extracts body", () => {
    const nodes = parse("::card\nContent here\n::")
    const bodyNode = nodes.find((n) => n.name === "ComponentBody")
    expect(bodyNode).toBeDefined()
    expect("::card\nContent here\n::".slice(bodyNode!.from, bodyNode!.to)).toBe("Content here")
  })

  it("handles multi-line body", () => {
    const names = nodeNames("::component\nLine 1\nLine 2\nLine 3\n::")
    expect(names).toContain("BlockComponent")
    expect(names).toContain("ComponentBody")
  })

  it("handles component with no attrs", () => {
    const names = nodeNames("::divider\n::")
    expect(names).toContain("BlockComponent")
    expect(names).toContain("ComponentName")
    expect(names).not.toContain("ComponentAttrs")
  })

  it("handles component with no body", () => {
    const names = nodeNames("::divider\n::")
    expect(names).toContain("BlockComponent")
  })
})
