/**
 * YAML language support for CodeMirror 6
 * Custom StreamLanguage tokenizer
 */

import { StreamLanguage, LanguageSupport } from '@codemirror/language'

const YAML_CONSTANTS = ['true', 'false', 'null', 'yes', 'no', 'on', 'off']

const yamlLanguage = StreamLanguage.define({
  token(stream): string | null {
    if (stream.eatSpace()) {
      return null
    }

    // Comment
    if (stream.match('#') !== null) {
      stream.skipToEnd()
      return 'comment'
    }

    // Document markers
    if (stream.sol() && stream.match('---') !== null) {
      return 'meta'
    }
    if (stream.sol() && stream.match('...') !== null) {
      return 'meta'
    }

    // Anchor and alias
    if (stream.match(/&[A-Za-z_][\w-]*/) !== null) {
      return 'labelName'
    }
    if (stream.match(/\*[A-Za-z_][\w-]*/) !== null) {
      return 'labelName'
    }

    // Tag
    if (stream.match(/![^\s]*/) !== null) {
      return 'tagName'
    }

    // Double-quoted string
    if (stream.match(/"(?:[^"\\]|\\.)*"/) !== null) {
      return 'string'
    }

    // Single-quoted string
    if (stream.match(/'(?:[^'\\]|\\.)*'/) !== null) {
      return 'string'
    }

    // Block scalar indicators
    if (stream.match(/[|>][+-]?\d*/) !== null) {
      return 'meta'
    }

    // Key: value pattern (key part)
    if (stream.sol() || stream.string.charAt(stream.start - 1) === ' ') {
      const keyMatch = stream.match(/[\w][\w.-]*(?=\s*:)/)
      if (keyMatch !== null) {
        return 'propertyName'
      }
    }

    // Colon separator
    if (stream.match(/:\s/) !== null) {
      return 'punctuation'
    }
    if (stream.match(/:$/) !== null && stream.eol()) {
      return 'punctuation'
    }

    // Numbers
    if (stream.match(/0x[0-9A-Fa-f]+/) !== null) {
      return 'number'
    }
    if (stream.match(/0o[0-7]+/) !== null) {
      return 'number'
    }
    if (stream.match(/[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?/) !== null) {
      return 'number'
    }
    if (stream.match(/[+-]?\.(inf|Inf|INF)/) !== null) {
      return 'number'
    }
    if (stream.match(/\.(nan|NaN|NAN)/) !== null) {
      return 'number'
    }

    // Constants (true, false, null, etc.)
    if (stream.match(/[A-Za-z_]\w*/) !== null) {
      const word = stream.current().toLowerCase()
      if (YAML_CONSTANTS.includes(word)) {
        return 'atom'
      }
      return null
    }

    // List indicator
    if (stream.match(/- /) !== null) {
      return 'punctuation'
    }

    // Flow indicators
    if (stream.match(/[{}[\],]/) !== null) {
      return 'bracket'
    }

    stream.next()
    return null
  },
})

/** YAML language support for CodeMirror */
export function yaml(): LanguageSupport {
  return new LanguageSupport(yamlLanguage)
}

export { yamlLanguage }
