import { c as T } from "../../chunks/runtime.js";
import { css as N, html as p } from "lit";
import { keyed as C } from "lit/directives/keyed.js";
import { createReactiveMap as I, findUtilityNetwork as M, queryAllJSON as $, getOrCreateMapValue as j } from "@arcgis/core/applications/Components/featureUtils.js";
import { stripHTML as k } from "@arcgis/core/applications/Components/stringUtils.js";
import w from "@arcgis/core/core/Collection.js";
import { ignoreAbortErrors as v } from "@arcgis/core/core/promiseUtils.js";
import { watch as A } from "@arcgis/core/core/reactiveUtils.js";
import * as U from "@arcgis/core/core/sql.js";
import V from "@arcgis/core/rest/networks/support/NetworkElement.js";
import x from "@arcgis/core/rest/networks/support/QueryAssociationsParameters.js";
import D from "@arcgis/core/rest/support/FeatureSet.js";
import P from "@arcgis/core/rest/support/Query.js";
import G from "@arcgis/core/widgets/Feature/FeatureViewModel.js";
import { LitElement as Q, renderElement as B } from "@arcgis/lumina";
import { debounce as L } from "@arcgis/toolkit/function";
/*! All material copyright Esri, All Rights Reserved, unless otherwise specified.
See https://js.arcgis.com/4.34/esri/copyright.txt for details.
v4.34.7 */
const O = N`.list-container{min-height:var(--calcite-spacing-xxxl)}.loading-container{display:flex;justify-content:center;padding:var(--calcite-spacing-md) 0;width:100%}.sticky-loading-container{display:flex;position:sticky;bottom:var(--calcite-spacing-sm);align-items:center;justify-content:center;z-index:2;margin:0;padding:0;height:var(--calcite-spacing-xxxl);pointer-events:none;height:500px}`, q = 100, E = {
  assetGroup: "assetgroup",
  assetType: "assettype"
}, S = "{00000000-0000-0000-0000-000000000000}";
class R extends Q {
  constructor() {
    super(...arguments), this._addFlowItem = (t) => {
      t && this.flowItems?.push(t);
    }, this._attachmentAssociations = new w(), this._attachmentFeatureCount = 0, this._cancelQuery = () => {
      const { _queryAbortController: t } = this;
      t && t.abort(), this._queryAbortController = null;
    }, this._cancelQueryFeatureCount = () => {
      const { _queryFeatureCountAbortController: t } = this;
      t && t.abort(), this._queryFeatureCountAbortController = null;
    }, this._connectivityAssociations = new w(), this._connectivityFeatureCount = 0, this._containerAssociations = new w(), this._containerFeatureCount = 0, this._contentAssociations = new w(), this._contentFeatureCount = 0, this._networkSourceIdsInUse = /* @__PURE__ */ new Set(), this._query = async (t) => {
      if (!t)
        return;
      await this._loadUtiltyNetworks();
      const { _queryAbortController: e } = this;
      this._destroyAssociatedFeatureViewModels(), this._clearFeatures(), this._featureCount && await this._queryAssociatedFeatures(t, { signal: e?.signal });
    }, this._queryController = async (t) => {
      this._cancelQuery();
      const e = new AbortController();
      this._queryAbortController = e, await v(this._query(t)), this._queryAbortController === e && (this._queryAbortController = null);
    }, this._queryFeatureCountController = async () => {
      this._loaded = !1, this._cancelQueryFeatureCount();
      const t = new AbortController();
      this._queryFeatureCountAbortController = t, await v(this._queryFeatureCount()), this._queryFeatureCountAbortController === t && (this._queryFeatureCountAbortController = null), this._loaded = !0;
    }, this._queryDebounced = L(this._queryController, q), this._queryFeatureCountDebounced = L(this._queryFeatureCountController, q), this._structureAssociations = new w(), this._structureFeatureCount = 0, this._queryAssociationType = async () => {
      this._activeAssociationType && this._queryDebounced(this._activeAssociationType);
    }, this._associationFeatures = I(), this._associationViewModels = I(), this._featureCount = 0, this._loaded = !1, this._queryAbortController = null, this._queryFeatureCountAbortController = null, this._queryPageAbortController = null, this.associationTypes = null, this.autoDestroyDisabled = !1, this.flowType = "feature-utility-network-associations", this.headingLevel = 2, this.source = "popup";
  }
  static {
    this.properties = { _activeAssociationType: 16, _associationFeatures: 16, _associationViewModels: 16, _canLoad: 16, _canQuery: 16, _featureCount: 16, _loaded: 16, _queryAbortController: 16, _queryFeatureCountAbortController: 16, _queryPageAbortController: 16, _state: 16, associationTypes: 0, autoDestroyDisabled: 5, description: 1, flowItems: 0, flowType: 1, graphic: 0, heading: 1, headingLevel: 9, layer: 0, map: 0, messages: 0, parentFeatureViewModel: 0, source: 1, spatialReference: 0, timeZone: 1, view: 0 };
  }
  static {
    this.styles = O;
  }
  get _globalId() {
    return (this._globalIdField && this.graphic?.attributes?.[this._globalIdField]) ?? null;
  }
  get _globalIdField() {
    return this.layer?.globalIdField;
  }
  get _objectId() {
    return (this._objectIdField && this.graphic?.attributes?.[this._objectIdField]) ?? null;
  }
  get _objectIdField() {
    return this.layer?.objectIdField;
  }
  get _supportsCacheHint() {
    return !!this.layer?.capabilities?.queryRelated?.supportsCacheHint;
  }
  get _utilityNetwork() {
    const { layer: t, map: e } = this;
    if (!t?.loaded || !e)
      return null;
    const s = this._isSubtypeSublayer(t) ? t.parent : t;
    return M(e, s);
  }
  get _canLoad() {
    return !!this.map;
  }
  get _canQuery() {
    return !!this.layer?.capabilities?.query?.supportsPagination;
  }
  get _state() {
    const { _canLoad: t, _canQuery: e, _featureCount: s, _loaded: o, _queryAbortController: i, _queryFeatureCountAbortController: a, _queryPageAbortController: u, associationTypes: c } = this;
    return a || t && !o ? "loading" : i || u ? "querying" : !this._globalId || !c || !e || !s ? "disabled" : "ready";
  }
  get heading() {
    return this._heading;
  }
  set heading(t) {
    this._heading = t;
  }
  async destroy() {
    await this.manager.destroy();
  }
  loaded() {
    this.manager.onLifecycle(() => [
      A(() => [
        this.graphic,
        this.layer,
        this.map,
        this.associationTypes,
        this._canQuery,
        this._objectId,
        this._globalId
      ], () => {
        this._queryFeatureCountDebounced(), this._queryAssociationType();
      }, { initial: !0 }),
      A(() => this._activeAssociationType, (t) => {
        this._queryDebounced(t);
      }),
      A(() => this._associationFeatures.values(), () => {
        this._setUpUtilityNetworkAssociationsViewModels();
      })
    ]), this.manager.onDestroy(() => {
      this._cancelQuery(), this._cancelQueryFeatureCount();
    });
  }
  _addAssociationTypeFlowItem() {
    this._addFlowItem(B(p`<arcgis-feature-utility-network-association-list .associationViewModels=${this._associationViewModels} .flowItems=${this.flowItems} .flowType=${this.flowType} .messages=${this.messages} .map=${this.map} .parentFeatureViewModel=${this.parentFeatureViewModel} .state=${this._state} .spatialReference=${this.spatialReference} .timeZone=${this.timeZone} .view=${this.view}></arcgis-feature-utility-network-association-list>`));
  }
  _clearAssociations() {
    this._attachmentAssociations.removeAll(), this._connectivityAssociations.removeAll(), this._containerAssociations.removeAll(), this._contentAssociations.removeAll(), this._structureAssociations.removeAll();
  }
  _clearFeatures() {
    this._associationFeatures.forEach((t) => t.removeAll()), this._associationFeatures.clear();
  }
  _compareByFeatureTitle(t, e) {
    return t.title.localeCompare(e.title, void 0, {
      numeric: !0
    });
  }
  async _countAssociatedFeatureCount(t, e, s, o, i) {
    const a = this._getFeatureQueryWhereClause(t, e, s, o);
    return await t.queryFeatureCount({
      where: a,
      outFields: ["*"],
      returnGeometry: !1
    }, {
      signal: i?.signal
    });
  }
  async _countAssociatedFeatures(t, e, s, o, i) {
    if (!e.length)
      return 0;
    const a = await this._findLayersBySourceId(t);
    await this._loadLayers(a);
    const u = a.map((r) => this._countAssociatedFeatureCount(r, e, s, o, i));
    return (await Promise.all(u)).reduce((r, d) => r + d, 0);
  }
  async _createAssociationFeatureObjects(t, e, s, o, i) {
    if (!t.length)
      return [];
    const a = /* @__PURE__ */ new Map(), u = Array.from(e.entries()).map(async ([r, d]) => {
      const l = await this._findLayersBySourceId(r);
      await this._loadLayers(l);
      const y = l.map((n) => this._queryLayer(n, d, s, o, i));
      (await Promise.all(y)).forEach((n) => {
        n.forEach((h) => {
          if (this.source === "popup" ? h.sourceLayer && h.getEffectivePopupTemplate() : !!h.sourceLayer) {
            const f = h.layer.globalIdField ?? "", g = h.attributes[f], b = a.get(g) ?? [];
            b.push(h), a.set(g, b);
          }
        });
      });
    });
    await Promise.all(u);
    const c = [];
    return await Promise.all(t.toArray().map(async (r) => {
      const { fromNetworkElement: d, toNetworkElement: l } = r, y = d.globalId === this._globalId ? l : d, m = a.get(y.globalId) ?? [];
      await Promise.all(m.map(async (n) => {
        const h = this._utilityNetwork?.getTerminalById(y?.terminalId)?.name, _ = await n.sourceLayer.getFeatureTitle(n) || this._getFeatureTitle(n);
        c.push({
          title: _,
          feature: n,
          association: r,
          terminalName: h
        });
      }));
    })), c;
  }
  _destroyAssociatedFeatureViewModels() {
    this._associationViewModels.forEach((t) => t.destroyAll());
  }
  _equals(t, e) {
    if (t.globalId === S && e.globalId === S) {
      let s = function(d, l) {
        return d.networkSourceId === l.networkSourceId && d.globalId === l.globalId && d.terminalId === l.terminalId && d.firstUnit === l.firstUnit && d.numUnits === l.numUnits;
      };
      const o = t.fromNetworkElement, i = t.toNetworkElement, a = e.fromNetworkElement, u = e.toNetworkElement, c = s(o, a), r = s(i, u);
      return c && r && t.associationType === e.associationType;
    }
    return t.globalId != null && e.globalId != null && t.globalId === e.globalId;
  }
  async _findLayersBySourceId(t) {
    const { _utilityNetwork: e, map: s } = this;
    e?.loaded || await e?.load();
    const o = e.getLayerIdBySourceId(t), i = s.allLayers.filter((c) => !!e?.isUtilityLayer(c) && c.layerId === o), a = s.allTables.filter((c) => !!e?.isUtilityLayer(c) && c.layerId === o);
    return i.concat(a).toArray();
  }
  _getAssociationsByType(t) {
    switch (t) {
      case "attachment":
        return this._attachmentAssociations;
      case "structure":
        return this._structureAssociations;
      case "connectivity":
        return this._connectivityAssociations;
      case "container":
        return this._containerAssociations;
      case "content":
        return this._contentAssociations;
    }
  }
  _getAssociationTypeTitle(t) {
    const { messages: e } = this;
    if (t.title)
      return t.title;
    switch (t.type) {
      case "attachment":
        return e?.associationsAttachments ?? this.messages?.noTitle ?? "";
      case "connectivity":
        return e?.associationsConnectivity ?? this.messages?.noTitle ?? "";
      case "structure":
        return e?.associationsStructure ?? this.messages?.noTitle ?? "";
      case "content":
        return e?.associationsContents ?? this.messages?.noTitle ?? "";
      case "container":
        return e?.associationsContainer ?? this.messages?.noTitle ?? "";
    }
  }
  _getFeatureCountForAssociationType(t) {
    switch (t) {
      case "attachment":
        return this._attachmentFeatureCount;
      case "structure":
        return this._structureFeatureCount;
      case "content":
        return this._contentFeatureCount;
      case "container":
        return this._containerFeatureCount;
      case "connectivity":
        return this._connectivityFeatureCount;
    }
  }
  _getFeatureQueryWhereClause(t, e, s, o) {
    const i = t.globalIdField, a = t.fieldsIndex.get(E.assetGroup), u = t.fieldsIndex.get(E.assetType), c = s != null, r = o != null, d = i ? U.sqlIn(i, e) : null, l = c ? `(${a?.name} = ${s})` : null, y = c && r ? `(${u?.name} = ${o})` : null;
    return [d, l, y].filter(Boolean).join(" AND ");
  }
  _getFeatureTitle(t) {
    const e = t.attributes, s = t.sourceLayer;
    if (!e || !s)
      return "";
    const o = "displayField" in s ? s.displayField : null, i = o != null ? e[o.toString()] : null, a = i != null ? i.toString() : null, u = t.getObjectId()?.toString();
    return a || u || "";
  }
  _isSubtypeGroupLayer(t) {
    return t != null && typeof t == "object" && "type" in t && t.type === "subtype-group" && "sublayers" in t;
  }
  _isSubtypeSublayer(t) {
    return t?.type === "subtype-sublayer";
  }
  async _loadUtiltyNetworks() {
    const t = this.map;
    if (!t)
      return;
    await Promise.allSettled(t.utilityNetworks?.map((s) => s.load()) ?? []);
    const e = this._utilityNetwork;
    if (e) {
      const s = (o) => {
        if ("layerId" in o && e.isUtilityLayer(o)) {
          const i = o.layerId != null ? e.getSourceIdByLayerId(o.layerId) : null;
          i != null && this._networkSourceIdsInUse.add(i);
        }
      };
      this._networkSourceIdsInUse = /* @__PURE__ */ new Set(), t.allLayers.forEach(s), t.allTables.forEach(s);
    }
  }
  async _loadLayers(t) {
    const e = t.filter((s) => !s.loaded).map((s) => s.load());
    e.length && await Promise.allSettled(e);
  }
  _matchesGlobalFeature(t, e) {
    return this._equals(t.association, e.association);
  }
  async _queryAssociatedFeatures(t, e) {
    const { layer: s, _globalId: o, associationTypes: i, _utilityNetwork: a, _canQuery: u, _associationFeatures: c } = this;
    if (await Promise.allSettled([s?.load(), a?.load()]), !u || !s || !i || !a)
      return;
    const r = this._getAssociationsByType(t.type), { associatedAssetGroup: d, associatedAssetType: l } = t, y = /* @__PURE__ */ new Map();
    r.forEach((n) => {
      const { fromNetworkElement: h, toNetworkElement: _ } = n, { networkSourceId: f, elementGlobalId: g } = h.globalId === o ? {
        networkSourceId: _.networkSourceId,
        elementGlobalId: _.globalId
      } : {
        networkSourceId: h.networkSourceId,
        elementGlobalId: h.globalId
      }, b = y.get(f) || [];
      b.push(g), y.set(f, b);
    });
    const m = await this._createAssociationFeatureObjects(r, y, d, l, e);
    this._parseFeatureObjects(m, c);
  }
  async _queryAssociations(t) {
    const { layer: e, _globalId: s, associationTypes: o, _utilityNetwork: i, _canQuery: a } = this;
    if (await Promise.allSettled([e?.load(), i?.load()]), this._clearAssociations(), !a || !e || !o || !i || !s)
      return;
    const u = this._isSubtypeSublayer(e) ? e.parent : e, c = new V({
      globalId: s,
      networkSourceId: i.getSourceIdByLayerId(u.layerId)
    }), r = /* @__PURE__ */ new Set();
    o.forEach((n) => {
      switch (n.type) {
        case "attachment":
        case "structure":
          r.add("attachment");
          break;
        case "container":
        case "content":
          r.add("containment");
          break;
        case "connectivity":
          r.add("connectivity"), r.add("junction-junction-connectivity"), r.add("junction-edge-from-connectivity"), r.add("junction-edge-midspan-connectivity"), r.add("junction-edge-to-connectivity");
          break;
      }
    });
    const d = await i?.queryAssociations(new x({
      elements: [c],
      types: Array.from(r)
    }), {
      signal: t?.signal
    }), l = /* @__PURE__ */ new Map(), y = /* @__PURE__ */ new Map();
    o.forEach((n) => {
      y.set(n.type, n), l.set(n.type, []);
    }), d.forEach((n) => {
      const { toNetworkElement: h, fromNetworkElement: _ } = n;
      switch (n.associationType) {
        case "attachment":
          if (_?.globalId === s) {
            if (this._shouldDiscardNetworkElement(h, "attachment", y))
              break;
            l.get("attachment")?.push(h.globalId), this._attachmentAssociations.add(n);
          } else {
            if (this._shouldDiscardNetworkElement(_, "structure", y))
              break;
            l.get("structure")?.push(_.globalId), this._structureAssociations.add(n);
          }
          break;
        case "connectivity":
        case "junction-edge-from-connectivity":
        case "junction-edge-midspan-connectivity":
        case "junction-edge-to-connectivity":
        case "junction-junction-connectivity":
          if (_?.globalId === s) {
            if (this._shouldDiscardNetworkElement(h, "connectivity", y))
              break;
            l.get("connectivity")?.push(h.globalId);
          } else {
            if (this._shouldDiscardNetworkElement(_, "connectivity", y))
              break;
            l.get("connectivity")?.push(_.globalId);
          }
          this._connectivityAssociations.add(n);
          break;
        case "containment":
          if (_?.globalId === s) {
            if (this._shouldDiscardNetworkElement(h, "content", y))
              break;
            l.get("content")?.push(h.globalId), this._contentAssociations.add(n);
          } else {
            if (this._shouldDiscardNetworkElement(_, "container", y))
              break;
            l.get("container")?.push(_.globalId), this._containerAssociations.add(n);
          }
          break;
      }
    });
    const m = o.map(async (n) => {
      const { associatedNetworkSourceId: h, associatedAssetGroup: _, associatedAssetType: f } = n, g = l.get(n.type), F = _ != null ? await this._countAssociatedFeatures(h, g, _, f, t) : g.length;
      switch (n.type) {
        case "attachment":
          this._attachmentFeatureCount = F;
          break;
        case "connectivity":
          this._connectivityFeatureCount = F;
          break;
        case "container":
          this._containerFeatureCount = F;
          break;
        case "content":
          this._contentFeatureCount = F;
          break;
        case "structure":
          this._structureFeatureCount = F;
          break;
      }
    });
    await Promise.allSettled(m);
  }
  async _queryFeatureCount() {
    await this._loadUtiltyNetworks();
    const { _queryFeatureCountAbortController: t, _canQuery: e } = this;
    if (!e) {
      this._featureCount = 0;
      return;
    }
    await this._queryAssociations(t), this._featureCount = this._attachmentFeatureCount + this._connectivityFeatureCount + this._containerFeatureCount + this._contentFeatureCount + this._structureFeatureCount;
  }
  async _queryLayer(t, e, s, o, i) {
    const a = this._getFeatureQueryWhereClause(t, e, s, o), u = new P({
      where: a,
      outFields: ["*"],
      cacheHint: this._supportsCacheHint
    }), c = D.fromJSON(await $(t, u, i));
    return c.features.forEach((r) => {
      const d = this._isSubtypeGroupLayer(t);
      r.layer = d ? t.findSublayerForFeature(r) : t, r.sourceLayer = d ? t.findSublayerForFeature(r) : t;
    }), c.features;
  }
  _parseFeatureObjects(t, e) {
    const s = I();
    t.forEach((o) => {
      const a = (o?.feature).sourceLayer;
      j(s, a, () => new w()).add(o);
    });
    for (const [o, i] of s)
      this._sortFeatureObjectsByTitle(i), e.set(o, i);
  }
  _selectAssociationType(t) {
    const { flowItems: e } = this;
    e && (this._activeAssociationType = t, this._setUpUtilityNetworkAssociationsViewModels(), this._addAssociationTypeFlowItem());
  }
  _setUpUtilityNetworkAssociationsViewModels() {
    this._associationViewModels.forEach((i, a) => {
      const u = this._associationFeatures.get(a);
      u ? i.forEach((c) => {
        u.find((d) => this._matchesGlobalFeature(c, d)) || (i.remove(c), i.length || this._associationViewModels.delete(a));
      }) : (i.removeAll(), this._associationViewModels.delete(a));
    });
    const { map: t, view: e, spatialReference: s, timeZone: o } = this;
    this._associationFeatures.forEach((i, a) => {
      const u = this._associationViewModels.get(a) || new w();
      i?.filter(Boolean).forEach((c, r) => {
        if (!u.some((l) => this._matchesGlobalFeature(l, c))) {
          const { association: l, feature: y, terminalName: m, title: n } = c;
          u.add({
            title: n,
            association: l,
            featureViewModel: new G({
              abilities: { utilityNetworkAssociationsContent: !1 },
              map: t,
              view: e,
              spatialReference: s,
              timeZone: o,
              graphic: y
            }),
            terminalName: m
          }, r);
        }
      }), this._associationViewModels.set(a, u);
    });
  }
  _shouldDiscardNetworkElement(t, e, s) {
    if (!t)
      return !1;
    const { networkSourceId: o } = t, i = s.get(e)?.associatedNetworkSourceId, a = this._networkSourceIdsInUse.has(o);
    return i != null && i !== o || !a;
  }
  _sortFeatureObjectsByTitle(t) {
    t.sort(this._compareByFeatureTitle);
  }
  render() {
    const { _state: t } = this;
    return p`<div><arcgis-feature-element-info .heading=${this.heading} .headingLevel=${this.headingLevel} .description=${this.description}></arcgis-feature-element-info>${t === "loading" ? this._renderLoading() : t === "disabled" ? this._renderAssociationNotFound() : this._renderContent()}</div>`;
  }
  _renderAssociationNotFound() {
    return p`<calcite-notice icon=information kind=info open scale=s width=full><div slot=message>${this.messages?.noAssociations}</div></calcite-notice>`;
  }
  _renderAssociationTypeList(t) {
    return this._getFeatureCountForAssociationType(t.type) > 0 ? this._renderAssociationTypeListItem(t) : null;
  }
  _renderAssociationTypeListItem(t) {
    const e = this._getAssociationTypeTitle(t);
    return C(`association-type-${t.type}`, p`<calcite-list-item .description=${k(t.description)} .label=${k(e)} .value=${t.type} @calciteListItemSelect=${() => this._selectAssociationType(t)}><calcite-icon flip-rtl icon=chevron-right scale=s slot=content-end></calcite-icon></calcite-list-item>`);
  }
  _renderContent() {
    const { _state: t, associationTypes: e, messages: s } = this, o = s?.associationsList ?? s?.noTitle ?? "";
    return C("list-container", p`<div class="list-container">${t === "ready" ? p`<div><calcite-list display-mode=flat .label=${o}>${e.map((i) => this._renderAssociationTypeList(i))}</calcite-list></div>` : null}${this._renderStickyLoading()}</div>`);
  }
  _renderLoading() {
    return p`<div class="loading-container">${this._renderLoadingIcon()}${this._renderStickyLoading()}</div>`;
  }
  _renderLoadingIcon() {
    return p`<calcite-loader inline label></calcite-loader>`;
  }
  _renderStickyLoading() {
    return this._state === "querying" ? p`<div class="sticky-loading-container">${this._renderLoadingIcon()}</div>` : null;
  }
}
T("arcgis-feature-utility-network-associations", R);
export {
  R as ArcgisFeatureUtilityNetworkAssociations
};
