import {
  HighlightStyle,
  StreamLanguage,
  StringStream,
  syntaxHighlighting
} from "@codemirror/language";
import { tags as t } from "@lezer/highlight";
const ATOMS = /* @__PURE__ */ new Set(["true", "false", "null"]);
const OPERATOR_RE = /^(?:==|!=|<=|>=|&&|\|\||[+\-*/%<>!?])/;
const IDENT_RE = /^[A-Z_$][\w$]*/i;
const NUMBER_RE = /^(?:0x[0-9a-f]+|\d+\.\d*(?:e[+-]?\d+)?|\d+(?:e[+-]?\d+)?)u?/i;
function eatString(stream) {
  const s = stream.string;
  const start = stream.pos;
  let i = start;
  let prefixLen = 0;
  while (prefixLen < 2 && /[br]/i.test(s[i + prefixLen] ?? "")) prefixLen++;
  const quote = s[i + prefixLen];
  if (quote !== '"' && quote !== "'") return false;
  const raw = /r/i.test(s.slice(i, i + prefixLen));
  i += prefixLen;
  const triple = s.slice(i, i + 3) === quote + quote + quote;
  const closer = triple ? quote + quote + quote : quote;
  i += closer.length;
  while (i < s.length) {
    const c = s[i];
    if (!raw && c === "\\") {
      i += 2;
      continue;
    }
    if (s.slice(i, i + closer.length) === closer) {
      i += closer.length;
      break;
    }
    if (!triple && (c === "\n" || c === "\r")) break;
    i++;
  }
  stream.pos = Math.min(i, s.length);
  return true;
}
const celStreamParser = {
  startState: () => ({ afterDot: false }),
  copyState: (state) => ({ afterDot: state.afterDot }),
  token(stream, state) {
    if (stream.eatSpace()) return null;
    if (stream.match(/^\.\.\./)) {
      state.afterDot = false;
      return null;
    }
    if (eatString(stream)) {
      state.afterDot = false;
      return "string";
    }
    if (stream.match(NUMBER_RE)) {
      state.afterDot = false;
      return "number";
    }
    const ident = stream.match(IDENT_RE);
    if (ident) {
      const word = ident[0];
      const afterDot = state.afterDot;
      state.afterDot = false;
      if (afterDot) return "propertyName";
      if (word === "in") return "keyword";
      if (ATOMS.has(word)) return "atom";
      return stream.peek() === "(" ? "variableName.function" : "variableName";
    }
    if (stream.match(OPERATOR_RE)) {
      state.afterDot = false;
      return "operator";
    }
    if (stream.eat(".")) {
      state.afterDot = true;
      return null;
    }
    state.afterDot = false;
    stream.next();
    return null;
  }
};
export const celLanguage = StreamLanguage.define(celStreamParser);
export function tokenizeCEL(line) {
  const stream = new StringStream(line, 4, 2);
  const state = celStreamParser.startState();
  const out = [];
  while (!stream.eol()) {
    stream.start = stream.pos;
    const token = celStreamParser.token(stream, state);
    if (stream.pos === stream.start) stream.next();
    out.push({ text: line.slice(stream.start, stream.pos), token });
  }
  return out;
}
const celHighlightStyle = HighlightStyle.define([
  { tag: t.keyword, color: "#5a3e8e" },
  // magenta — control keyword `in`
  { tag: t.operator, color: "#5a3e8e" },
  // magenta — && || == + - …
  { tag: t.string, color: "#385f0d" },
  // green — strings / bytes
  { tag: t.number, color: "#965027" },
  // orange — numbers
  { tag: t.atom, color: "#965027" },
  // orange — true / false / null
  { tag: t.variableName, color: "#343b58" },
  // navy — variables
  { tag: t.propertyName, color: "#0f4b6e" },
  // cyan — object properties / member access
  { tag: t.function(t.variableName), color: "#2959aa" }
  // blue — function calls
]);
export function celHighlighting() {
  return [celLanguage, syntaxHighlighting(celHighlightStyle)];
}
