/**
 * Shared types for the markdown rule engine.
 *
 * Kept in a separate module so rules and the engine can all import
 * from one place without creating circular dependencies.
 */

import type { SyntaxNode } from "@lezer/common"

// ── Parse context ────────────────────────────────────────────────────

export interface ParseContext {
  doc: string
  cursorPos?: number
}

// ── Decoration range ─────────────────────────────────────────────────

export interface DecorationRange {
  type: "hidden" | "content"
  from: number
  to: number
  className?: string
}

// ── Token types ──────────────────────────────────────────────────────

/**
 * Base for all parsed tokens.
 * Each rule supplies wrapperAttrs so the decoration builder never
 * needs to type-switch on the token shape.
 *
 * `nodeWrapper` signals to the ProseMirror plugin that the entire text
 * block should be wrapped in a node-level decoration (e.g. a callout
 * card) so the whole block renders as one visual unit.  Only block-
 * level tokens use this; inline tokens leave it empty.
 */
export interface ParsedToken {
  type: string
  decorationRanges: DecorationRange[]
  wrapperAttrs?: Record<string, string>
  nodeWrapper?: { className: string; attrs?: Record<string, string> }
}

export interface TokenDecoration extends ParsedToken {
  type: string
}

export interface PageRefDecoration extends ParsedToken {
  type: "page-ref"
  pageName: string
  alias?: string
}

export interface BlockRefDecoration extends ParsedToken {
  type: "block-ref"
  blockId: string
}

export interface TagDecoration extends ParsedToken {
  type: "tag"
  tag: string
}

export interface HighlightDecoration extends ParsedToken {
  type: "highlight"
}

export interface InlineMathDecoration extends ParsedToken {
  type: "inline-math"
}

export interface ImageDecoration extends ParsedToken {
  type: "image"
}

// ── Block decoration ─────────────────────────────────────────────────

export type TaskState =
  | "TODO"
  | "DOING"
  | "DONE"
  | "LATER"
  | "NOW"
  | "WAITING"
  | "CANCELLED"

export type CalloutType = "NOTE" | "WARNING" | "TIP" | "DANGER" | "INFO"

export interface BlockDecoration extends ParsedToken {
  type:
    | "heading"
    | "task"
    | "blockquote"
    | "callout"
    | "horizontal-rule"
    | "table"
  metadata?: {
    level?: number
    taskState?: TaskState
    calloutType?: CalloutType
  }
}

// ── Property ─────────────────────────────────────────────────────────

export interface PropertyInfo {
  key: string
  value: string
  keyRange: [number, number]
  delimiterRange: [number, number]
  valueRange: [number, number]
}

// ── Parser output ────────────────────────────────────────────────────

export interface ParsedDecorations {
  content: (
    | TokenDecoration
    | PageRefDecoration
    | BlockRefDecoration
    | TagDecoration
    | HighlightDecoration
    | InlineMathDecoration
    | ImageDecoration
  )[]
  properties: PropertyInfo[]
  blocks: BlockDecoration[]
}

// ── Rule interfaces ──────────────────────────────────────────────────

export interface MarkdownRule<T = unknown> {
  name: string
  nodeTypes?: string[]
  match(node: SyntaxNode, ctx: ParseContext): boolean
  run(node: SyntaxNode, ctx: ParseContext): T | null
}

// ── Block Rule ────────────────────────────────────────────────────────
// Matches Lezer AST block nodes (e.g., Blockquote, Heading) and produces
// BlockDecoration covering the full node range.

export interface BlockRule {
  name: string
  nodeTypes: string[]
  match(node: SyntaxNode, ctx: ParseContext): boolean
  run(node: SyntaxNode, ctx: ParseContext): BlockDecoration | null
}
