/* COPYRIGHT Esri - https://js.arcgis.com/5.1/LICENSE.txt */
import { fetchT9nStringsBundle as v } from "@arcgis/toolkit/intl";
import { g as L } from "./runtime.js";
import { a as q, D as P, b as C, q as T, n as w, c as M, e as F, L as V, h as $, E as k, i as _ } from "./language-defaults-base.js";
import x from "@arcgis/core/portal/Portal.js";
import { l as A } from "./utils.js";
function y(t) {
  for (const e of t) {
    if (e instanceof C)
      return e;
    if (e.isCollection && "variables" in e) {
      const o = y(
        e.variables.filter(
          (a) => a.type !== "group"
        )
      );
      if (o)
        return o;
    }
  }
}
function S(t, e) {
  return `${t}:${e}`;
}
function B(t) {
  if (t) {
    for (const e of t)
      if (e.type === "dataCatalogDatastore")
        return e.definition;
  }
}
async function N(t) {
  const e = new x({ url: t.portal.url });
  return await e.load(), new P({
    itemId: t.id,
    serviceUrl: t.serviceUrl,
    portal: e
  });
}
async function E(t) {
  return A(t) ? await N(t) : t;
}
function I(t, e, o) {
  let a = `**${t}**`;
  return e.type && (a += `  
${e.type}`), o && (a += `  
Datastore: ${o}`), { value: a };
}
function W(t, e) {
  let o = `**${t.name}**`;
  return t.serverType && (o += `  
${t.serverType}`), o += `  
Nullable: ${t.nullable ? "yes" : "no"}`, o += `  
Table: ${e}`, { value: o };
}
function U(t, e, o) {
  return t.map((a) => {
    const r = T(a.name, o);
    return {
      name: a.name,
      normalizedName: w(a.name),
      quotedName: r === a.name ? void 0 : r,
      dataType: a.serverType,
      nullable: a.nullable,
      completionLabel: a.name,
      insertText: r,
      detail: [a.serverType, a.nullable ? "nullable" : "not null"].filter(Boolean).join(" | "),
      documentation: W(a, e)
    };
  });
}
function z(t, e, o, a) {
  const r = M(t.name, a), s = t.name.split("."), n = F(t.name);
  return {
    id: S(e, t.name),
    name: t.name,
    normalizedName: w(t.name),
    quotedName: r === t.name ? void 0 : r,
    description: t.type,
    schema: s.length >= 2 ? s.at(-2) : void 0,
    catalog: s.length >= 3 ? s.at(-3) : void 0,
    completionLabel: t.name,
    insertText: r,
    detail: [t.type, o].filter(Boolean).join(" | "),
    documentation: I(n, t, o),
    columns: []
  };
}
async function K(t, e) {
  const o = y(t.dictionaryVariables);
  if (!o)
    return { tables: [] };
  await o.loadSource();
  const a = o.datastoreInfo, r = a?.datastoreId;
  if (!r)
    return { tables: [] };
  const s = o.tableVariables.map(
    (n) => z(n.datasetInfo, r, a?.name, e)
  );
  return {
    datastore: {
      id: r,
      displayName: a?.name,
      databasePlatform: a?.databasePlatform
    },
    tables: s
  };
}
async function R(t) {
  const e = B(t?.variables);
  if (!e)
    return q(void 0);
  const a = await (await E(e)).fetchInfo();
  return q(a.databasePlatform);
}
class j extends V {
  /**
   * Per-model update chaining to serialize profile updates. see arcade-defaults for rationale.
   */
  #e = /* @__PURE__ */ new Map();
  /**
   * Per-model, per-table column load caching to avoid redundant loads when multiple requests for the same table(s) are made before the first load completes.
   */
  #t = /* @__PURE__ */ new Map();
  #a;
  constructor(e) {
    super(e, {
      apiPath: "./assets/sql-layer/api",
      apiPrefix: "sql-layer-api.t9n."
    });
    const o = _(e);
    this.dialectId = o;
  }
  getWorkerHostExtension() {
    return {
      getSqlLayerDialectSpec: async () => await this.getDialectSpec(),
      getSqlLayerColumnsForModel: async (e, o) => await this._loadSqlLayerColumnsForModel(e, o)
    };
  }
  async getDialectSpec() {
    return this.#a ??= $(this.languageId), await this.#a;
  }
  disposeForModel(e) {
    this.#t.delete(this._getApiKey(e)), super.disposeForModel(e);
  }
  async setProfileForModel(e, o, a) {
    const r = this._getApiKey(e), n = (this.#e.get(r) || Promise.resolve()).then(async () => {
      const f = await v(
        a.locale,
        L("./assets/editor-profile/t9n"),
        "messages."
      );
      if (!f)
        throw new Error(`Failed to load the language bundle for ${a.locale}`);
      this.disposeForModel(e);
      const u = new k(o, f, a.locale);
      this._modelToProfileMap.set(r, u);
      const g = await K(u, await this.getDialectSpec());
      this.updateApiContextForModel(e, {
        locale: a.locale,
        snippets: a.snippets,
        sqlProfile: g
      });
    }), l = n.finally(() => {
      this.#e.get(r) === l && this.#e.delete(r);
    });
    return this.#e.set(r, l), await n;
  }
  async _loadSqlLayerColumnsForModel(e, o) {
    if (!o.length)
      return [];
    const a = this._getApiKey(e), r = this.getApiContextForModel(e), s = r.sqlProfile, n = this._modelToProfileMap.get(a), l = n ? y(n.dictionaryVariables) : void 0;
    if (!s || !l)
      return [];
    await l.loadSource();
    const u = l.datastoreInfo?.datastoreId;
    if (!u)
      return [];
    const g = new Map(
      l.tableVariables.map((i) => [
        S(u, i.datasetInfo.name),
        i
      ])
    );
    let d = this.#t.get(a);
    d || (d = /* @__PURE__ */ new Map(), this.#t.set(a, d));
    const h = await Promise.all(
      o.map(async (i) => {
        const b = s.tables.find((c) => c.id === i);
        if (b?.columns.length)
          return { tableId: i, columns: b.columns };
        let m = d.get(i);
        return m || (m = (async () => {
          const c = g.get(i);
          return c ? (await c.loadSource(), U(
            c.fieldInfos,
            c.datasetInfo.name,
            await this.getDialectSpec()
          )) : [];
        })(), d.set(i, m)), { tableId: i, columns: await m };
      })
    ), D = this._mergeLoadedColumns(s, h);
    return D !== s && this.updateApiContextForModel(e, { ...r, sqlProfile: D }), h;
  }
  _mergeLoadedColumns(e, o) {
    const a = new Map(o.map((n) => [n.tableId, n.columns]));
    let r = !1;
    const s = e.tables.map((n) => n.columns.length || !a.has(n.id) ? n : (r = !0, {
      ...n,
      columns: a.get(n.id) ?? n.columns
    }));
    return r ? { ...e, tables: s } : e;
  }
}
const p = /* @__PURE__ */ new Map();
function X(t) {
  let e = p.get(t);
  return e || (e = new j(t), p.set(t, e)), e;
}
function Y(t) {
  return p.get(t);
}
function Z() {
  return [...p.values()];
}
export {
  R as a,
  Y as b,
  X as c,
  Z as g
};
