import { Emitter as S, languages as p } from "monaco-editor";
import "monaco-editor/esm/vs/editor/standalone/browser/standaloneServices.js";
import "monaco-editor/esm/vs/editor/standalone/common/standaloneTheme.js";
import "monaco-editor/esm/vs/platform/hover/browser/hover.js";
import "monaco-editor/esm/vs/editor/common/languages/supports/tokenization.js";
import "monaco-editor/esm/vs/base/browser/dom.js";
import "monaco-editor/esm/vs/editor/browser/editorDom.js";
import "monaco-editor/esm/vs/editor/browser/controller/mouseTarget.js";
import { i as E } from "./monaco-importer.js";
import { Deferred as m } from "@arcgis/toolkit/promise";
import { a as d } from "./sql-expr-defaults.js";
import { debounce as f } from "@arcgis/toolkit/function";
import { rethrowError as g } from "@arcgis/toolkit/log";
import { g as N } from "./sql-expr-service-accessors.js";
/*! All material copyright Esri, All Rights Reserved, unless otherwise specified.
See https://js.arcgis.com/5.0/esri/copyright.txt for details.
v5.0.0-next.128 */
let h = new m();
class C {
  constructor(e) {
    this._defaults = e, this._worker = null, this._client = null, this._configChangeListener = this._defaults.onDidChange(() => this.stopWorker());
  }
  dispose() {
    this._configChangeListener.dispose(), this.stopWorker();
  }
  stopWorker() {
    this._worker && (this._worker.dispose(), this._worker = null, h = new m()), this._client = null;
  }
  /**
   * Wait for the worker to be ready.
   * @returns A promise that resolves when the worker is ready.
   */
  static async waitForWorker() {
    return await h.promise;
  }
  async _getClientProxy() {
    const e = await E();
    if (!this._client) {
      const { languageId: t } = this._defaults;
      this._worker = e.createWebWorker({
        moduleId: "SqlExprWorker",
        label: t,
        createData: { languageId: t },
        host: this._defaults.workerHost
      }), h.resolve(this._worker), this._client = this._worker.getProxy();
    }
    return await this._client;
  }
  async getLanguageServiceWorker(...e) {
    const t = await this._getClientProxy();
    return await this._worker?.withSyncedResources(e), t;
  }
}
const A = [
  "AND",
  "AS",
  "BOTH",
  "CASE",
  "CAST",
  "CURRENT_DATE",
  "CURRENT_TIME",
  "CURRENT_TIMESTAMP",
  "DATE",
  "DAY",
  "DOY",
  "DOW",
  "ELSE",
  "END",
  "ESCAPE",
  "FALSE",
  "FLOAT",
  "FOR",
  "FROM",
  "HOUR",
  "IN",
  "INT",
  "INTEGER",
  "INTERVAL",
  "LEADING",
  "LIKE",
  "MINUTE",
  "MONTH",
  "POSITION",
  "REAL",
  "SECOND",
  "SMALLINT",
  "THEN",
  "TIME",
  "TIMESTAMP",
  "TIMEZONE_HOUR",
  "TIMEZONE_MINUTE",
  "TO",
  "TRAILING",
  "TRIM",
  "TRUE",
  "VARCHAR",
  "WEEK",
  "WHEN",
  "WITH",
  "YEAR",
  "ZONE"
], L = [
  // Logical
  "AND",
  "BETWEEN",
  "LIKE",
  "NOT",
  "OR",
  // Predicates
  "IS",
  "NULL"
], x = [
  // Conversion
  "CAST",
  // Datetime
  "EXTRACT",
  "CURRENT_DATE",
  "CURRENT_TIME",
  "CURRENT_TIMESTAMP",
  "CURRENT_USER",
  // Mathematical
  "ABS",
  "ACOS",
  "ASIN",
  "ATAN",
  "CEILING",
  "COS",
  "FLOOR",
  "LOG",
  "LOG10",
  "MOD",
  "NULLIF",
  "POWER",
  "ROUND",
  "SIGN",
  "SIN",
  "TAN",
  "TRUNCATE",
  // String
  "CHAR_LENGTH",
  "COALESCE",
  "CONCAT",
  "LOWER",
  "POSITION",
  "SUBSTRING",
  "TRIM",
  "UPPER"
], R = {
  comments: {
    lineComment: "--",
    blockComment: ["/*", "*/"]
  },
  brackets: [
    ["{", "}"],
    ["[", "]"],
    ["(", ")"]
  ],
  autoClosingPairs: [
    { open: "{", close: "}" },
    { open: "[", close: "]" },
    { open: "(", close: ")" },
    { open: '"', close: '"' },
    { open: "'", close: "'" }
  ],
  surroundingPairs: [
    { open: "{", close: "}" },
    { open: "[", close: "]" },
    { open: "(", close: ")" },
    { open: '"', close: '"' },
    { open: "'", close: "'" }
  ]
}, M = {
  defaultToken: "",
  tokenPostfix: ".arcgis",
  ignoreCase: !0,
  brackets: [
    { open: "[", close: "]", token: "delimiter.square" },
    { open: "(", close: ")", token: "delimiter.parenthesis" }
  ],
  keywords: A,
  operators: L,
  builtinFunctions: x,
  builtinVariables: [],
  tokenizer: {
    root: [
      { include: "@comments" },
      { include: "@whitespace" },
      { include: "@numbers" },
      { include: "@strings" },
      { include: "@complexIdentifiers" },
      { include: "@scopes" },
      [/[;,.]/, "delimiter"],
      [/[()]/, "@brackets"],
      [
        /[\w@#$]+/,
        {
          cases: {
            "@operators": "operator",
            "@builtinVariables": "predefined",
            "@builtinFunctions": "predefined",
            "@keywords": "keyword",
            "@default": "identifier"
          }
        }
      ],
      [/[<>=!%&+\-*/|~^]/, "operator"]
    ],
    whitespace: [[/\s+/, "white"]],
    comments: [
      [/--+.*/, "comment"],
      [/\/\*/, { token: "comment.quote", next: "@comment" }]
    ],
    comment: [
      [/[^*/]+/, "comment"],
      // Not supporting nested comments, as nested comments seem to not be standard?
      // i.e. http://stackoverflow.com/questions/728172/are-there-multiline-comment-delimiters-in-sql-that-are-vendor-agnostic
      // [/\/\*/, { token: 'comment.quote', next: '@push' }],    // nested comment not allowed :-(
      [/\*\//, { token: "comment.quote", next: "@pop" }],
      [/./, "comment"]
    ],
    numbers: [
      [/0[xX][0-9a-fA-F]*/, "number"],
      [/[$][+-]*\d*(\.\d*)?/, "number"],
      [/((\d+(\.\d*)?)|(\.\d+))([eE][\-+]?\d+)?/, "number"]
    ],
    strings: [
      [/N'/, { token: "string", next: "@string" }],
      [/'/, { token: "string", next: "@string" }]
    ],
    string: [
      [/[^']+/, "string"],
      [/''/, "string"],
      [/'/, { token: "string", next: "@pop" }]
    ],
    complexIdentifiers: [[/"/, { token: "identifier.quote", next: "@quotedIdentifier" }]],
    quotedIdentifier: [
      [/[^"]+/, "identifier"],
      [/""/, "identifier"],
      [/"/, { token: "identifier.quote", next: "@pop" }]
    ],
    scopes: [
      [/(BEGIN|CASE)\b/i, { token: "keyword.block" }],
      [/END\b/i, { token: "keyword.block" }],
      [/WHEN\b/i, { token: "keyword.choice" }],
      [/THEN\b/i, { token: "keyword.choice" }]
    ]
  }
};
class D {
  constructor(e, t) {
    this._worker = e, this._defaults = t;
  }
  async provideCompletionItems(e, t) {
    try {
      const r = await this._worker(e.uri), n = e.getWordUntilPosition(t), s = {
        startLineNumber: t.lineNumber,
        endLineNumber: t.lineNumber,
        startColumn: n.startColumn,
        endColumn: n.endColumn
      }, c = this._defaults.getApiContextForModel(e.uri);
      return await r.doComplete(e.uri.toString(), s, t, c);
    } catch (r) {
      return g("SqlExprCompletionProvider")(r), { suggestions: [] };
    }
  }
}
class b {
  constructor(e, t, {
    defaults: r,
    diagnosticService: n
  }) {
    this._languageId = e, this._worker = t, this._disposables = [], this._modelListeners = /* @__PURE__ */ new Map(), this._diagnosticsService = n, this._defaults = r, E().then((s) => {
      const c = (o) => {
        const i = o.getLanguageId();
        if (i !== this._languageId)
          return;
        const l = f(() => {
          this._doValidate(o, i).catch((T) => {
            throw T;
          });
        }), w = o.onDidChangeContent(l), I = o.onDidChangeAttached(l);
        this._modelListeners.set(o.uri.toString(), [w, I]), this._doValidate(o, i).catch(g("SqlExprDiagnosticsAdapter"));
      }, u = (o) => {
        const i = o.uri.toString();
        s.setModelMarkers(o, this._languageId, []);
        const l = this._modelListeners.get(i);
        if (l) {
          for (; l.length; )
            l.pop()?.dispose();
          this._modelListeners.delete(i);
        }
      };
      this._disposables.push(s.onDidCreateModel(c)), this._disposables.push(s.onWillDisposeModel((o) => u(o))), this._disposables.push(
        s.onDidChangeModelLanguage((o) => {
          u(o.model), c(o.model);
        })
      ), this._disposables.push(
        r.onDidChange(() => {
          s.getModels().forEach((o) => {
            o.getLanguageId() === this._languageId && (u(o), c(o));
          });
        })
      ), this._disposables.push(
        r.onModelContextDidChange((o) => {
          s.getModels().forEach((i) => {
            i.getLanguageId() === this._languageId && i.uri.toString() === o && this._doValidate(i, this._languageId).catch(g("SqlExprDiagnosticsAdapter"));
          });
        })
      ), this._disposables.push({
        dispose: () => {
          this._modelListeners.forEach((o) => o.forEach((i) => i.dispose())), this._modelListeners.clear();
        }
      }), s.getModels().forEach(c);
    });
  }
  async _doValidate(e, t) {
    const r = await E();
    if (e.isAttachedToEditor())
      try {
        const n = await this._worker(e.uri), s = this._defaults.getApiContextForModel(e.uri), c = await n.doValidation(e.uri.toString(), s);
        this._diagnosticsService.fireDiagnosticsChange(e.uri, c), r.setModelMarkers(e, t, c);
      } catch (n) {
        g("SqlExprDiagnosticsAdapter")(n);
      }
  }
}
let _;
async function X(...a) {
  return await C.waitForWorker(), await new Promise((e, t) => {
    if (!_) {
      t(new Error("sql expression worker not registered!"));
      return;
    }
    e(_(...a));
  });
}
class O {
  constructor() {
    this._onDiagnosticsChange = new S();
  }
  /**
   * An event to signal changes to the diagnostics.
   * The event value is the uri string and the diagnostics.
   */
  get onDiagnosticsChange() {
    return this._onDiagnosticsChange.event;
  }
  /**
   * Fires the diagnostics change event.
   * @param uri The uri of the model for which the diagnostics changed.
   * @param diagnostics The diagnostics for the model.
   */
  fireDiagnosticsChange(e, t) {
    this._onDiagnosticsChange.fire({ uri: e, diagnostics: t });
  }
}
const k = new O();
async function $() {
  return await N(), k;
}
function z(a) {
  const e = new C(a), t = async (...n) => await e.getLanguageServiceWorker(...n);
  _ = t, p.setMonarchTokensProvider(d.languageId, M), p.setLanguageConfiguration(d.languageId, R);
  const r = new D(t, d);
  p.registerCompletionItemProvider(d.languageId, r), new b(a.languageId, t, {
    defaults: a,
    diagnosticService: k
  });
}
export {
  $ as getSqlExprDiagnosticService,
  X as getSqlExprWorker,
  z as setupMode
};
