import { type InlineContext, type MarkdownConfig } from "@lezer/markdown"

/**
 * InlineParser for Comark inline components:
 *
 *   :icon-check              (standalone — no body, no attrs)
 *   :priority{value="high"}  (with attrs)
 *   :badge[Active]{color="green"}  (with body + attrs)
 *
 * Produces an InlineComponent node with children:
 *   ComponentName, ComponentBody (if [body] present), ComponentAttrs (if {attrs} present)
 *
 * Emoji syntax (`:smile:`) is distinguished by the trailing colon — if
 * `:name` is followed by `:`, this parser returns -1 so the Emoji parser
 * (if registered) can handle it.
 */

const COMPONENT_RE = /^:([\w-]+)/
const EMOJI_TAIL_RE = /^:([\w-]+):/
const BODY_RE = /^\[([^\]]*)\]/
const ATTRS_RE = /^\{[^}]*\}/

function parseInlineComponent(cx: InlineContext, next: number, pos: number): number {
  if (next !== 58 /* colon */) return -1

  const text = cx.slice(pos, cx.end)

  // Reject if this looks like emoji syntax (:name:)
  if (EMOJI_TAIL_RE.test(text)) return -1

  const nameMatch = text.match(COMPONENT_RE)
  if (!nameMatch) return -1

  const name = nameMatch[1]!
  let cur = pos + nameMatch[0].length
  let bodyStart = -1
  let bodyEnd = -1
  let attrsStart = -1
  let attrsEnd = -1

  // Optional [body]
  const bodyRest = cx.slice(cur, cx.end)
  const bodyMatch = bodyRest.match(BODY_RE)
  if (bodyMatch) {
    bodyStart = cur + 1 // skip '['
    bodyEnd = cur + bodyMatch[0].length - 1 // exclude ']'
    cur += bodyMatch[0].length
  }

  // Optional {attrs}
  const attrsRest = cx.slice(cur, cx.end)
  const attrsMatch = attrsRest.match(ATTRS_RE)
  if (attrsMatch) {
    attrsStart = cur
    attrsEnd = cur + attrsMatch[0].length
    cur += attrsMatch[0].length
  }

  const children: import("@lezer/markdown").Element[] = [
    cx.elt("ComponentName", pos + 1, pos + 1 + name.length),
  ]

  if (bodyStart !== -1) {
    children.push(cx.elt("ComponentBody", bodyStart, bodyEnd))
  }

  if (attrsStart !== -1) {
    children.push(cx.elt("ComponentAttrs", attrsStart, attrsEnd))
  }

  cx.addElement(cx.elt("InlineComponent", pos, cur, children))
  return cur
}

export const inlineComponentConfig: MarkdownConfig = {
  defineNodes: [
    { name: "InlineComponent" },
    { name: "ComponentName" },
    { name: "ComponentBody" },
    { name: "ComponentAttrs" },
  ],
  parseInline: [
    { name: "InlineComponent", parse: parseInlineComponent },
  ],
}
