import {
  syntaxHighlight as _syntaxHighlight,
  detectLanguage as _detectLanguage,
  _diff,
  _patch,
  BUILTIN_THEME_NAMES as _builtinThemeNames,
 } from "agency-lang/stdlib-lib/syntax.js"

/** @module
  @summary Highlight code and produce terminal diffs or unified patches.
  Highlight code and compare versions of text. Use `diff` for terminal
  display or `patch` to produce a unified diff for `git apply`.

  ```ts
  import { highlight } from "std::syntax"

  node main() {
    print(highlight("const x = 1", language: "typescript"))
  }
  ```
*/

export def detectLanguage(code: string): string {
  """
  Guess a code snippet's language, or return "plaintext" when unknown.
  Detection is less reliable on short or ambiguous snippets.
  """
  return _detectLanguage(code)
}

/** A text style modifier applied to a token's color. */
export type Style = "bold" | "italic" | "underline" | "dim"

/**
  The style for one token class. `color` is a hex string (e.g. "#569CD6") or a
  termcolors named color (e.g. "red", "brightGreen"). `styles` optionally adds
  bold / italic / underline / dim.
*/
export type TokenStyle = {
  color: string;
  styles?: Style[]
}

/**
  A custom color scheme. Each field is a highlight.js token class. The
  non-identifier classes use camelCase names (e.g. `builtIn` -> `built_in`,
  `metaKeyword` -> `meta-keyword`). All fields are optional and merge over the
  "vscode-dark" scheme.
*/
export type ColorScheme = {
  keyword?: TokenStyle;
  builtIn?: TokenStyle;
  type?: TokenStyle;
  literal?: TokenStyle;
  number?: TokenStyle;
  regexp?: TokenStyle;
  string?: TokenStyle;
  subst?: TokenStyle;
  symbol?: TokenStyle;
  class?: TokenStyle;
  function?: TokenStyle;
  title?: TokenStyle;
  params?: TokenStyle;
  comment?: TokenStyle;
  doctag?: TokenStyle;
  meta?: TokenStyle;
  section?: TokenStyle;
  tag?: TokenStyle;
  name?: TokenStyle;
  attr?: TokenStyle;
  attribute?: TokenStyle;
  variable?: TokenStyle;
  bullet?: TokenStyle;
  code?: TokenStyle;
  emphasis?: TokenStyle;
  strong?: TokenStyle;
  formula?: TokenStyle;
  link?: TokenStyle;
  quote?: TokenStyle;
  addition?: TokenStyle;
  deletion?: TokenStyle;
  default?: TokenStyle;
  metaKeyword?: TokenStyle;
  metaString?: TokenStyle;
  builtinName?: TokenStyle;
  selectorTag?: TokenStyle;
  selectorId?: TokenStyle;
  selectorClass?: TokenStyle;
  selectorAttr?: TokenStyle;
  selectorPseudo?: TokenStyle;
  templateTag?: TokenStyle;
  templateVariable?: TokenStyle
}

/** The names of all built-in color schemes (valid string values for `theme`). */
export static const colorSchemes: string[] = _builtinThemeNames

// Naming each scheme instead of taking a plain `string` keeps the tool
// schema small and tells a model which values are actually accepted.
/**
  A built-in color scheme accepted by `highlight` and `diff`.
*/
export type ThemeName =
  | "vscode-dark"
  | "github-dark"
  | "monokai"
  | "dracula"
  | "nord"
  | "github"
  | "a11y-dark"
  | "a11y-light"

/**
  Returns ANSI terminal styling.
  When `language` is "markdown", fenced code blocks use the default palette
  regardless of `theme`.
*/
export def highlight(
  code: string,
  language: string = "plaintext",
  theme: ThemeName = "vscode-dark",
): string {
  """
  Add ANSI syntax highlighting to code for terminal display.

  @param language - A highlight.js language name, or "auto" to guess.
  """
  return _syntaxHighlight(code, language, theme)
}

/**
Use for displaying changes to a person. With `language` and color enabled,
changed lines use syntax highlighting on red or green backgrounds. Background
padding is limited to the terminal width. Use `patch` for output to apply with Git.
*/
@capabilities(terminal)
export def diff(
  oldText: string,
  newText: string,
  context: number = -1,
  lineNumbers: boolean = false,
  color: "auto" | boolean = "auto",
  oldLabel: string = "",
  newLabel: string = "",
  ignoreWhitespace: boolean = false,
  hunkHeaders: boolean = false,
  summary: boolean = false,
  language: string = "",
  theme: ThemeName = "vscode-dark",
): string {
  """
  Compare two texts for terminal display, highlighting changed words.

  @param context - Unchanged lines around each change, or -1 for the full text.
  @param color - "auto" colors terminal output; true always colors; false disables color.
  @param oldLabel - Optional label for the original text header.
  @param newLabel - Optional label for the updated text header.
  @param ignoreWhitespace - Treat whitespace-only changes as equal.
  @param hunkHeaders - Include location headers between change regions.
  @param summary - Include insertion and deletion counts.
  @param language - Highlight changed lines using this language, or "auto" to guess.
  @param theme - Color scheme for syntax-highlighted changes.
  """
  return _diff(
    oldText,
    newText,
    context,
    lineNumbers,
    color,
    oldLabel,
    newLabel,
    ignoreWhitespace,
    hunkHeaders,
    summary,
    language,
    theme,
  )
}

/**
An empty `oldText` creates a file-creation patch. An empty `newText` creates
a deletion patch. This function returns patch text without changing files.
*/
export def patch(
  oldText: string,
  newText: string,
  filename: string,
  context: number = 3,
  ignoreWhitespace: boolean = false,
  newFilename: string = "",
): string {
  """
  Produce a unified diff suitable for git apply.

  @param filename - Path to use in the patch headers.
  @param context - Unchanged lines around each change.
  @param ignoreWhitespace - Treat whitespace-only changes as equal.
  @param newFilename - Optional new path for a rename.
  """
  return _patch(oldText, newText, filename, context, ignoreWhitespace, newFilename)
}
