/* COPYRIGHT Esri - https://js.arcgis.com/1.2/LICENSE.txt */
import { c as customElement } from "../../chunks/runtime.js";
import { c as getFeatureLayerView, i as getIdSets, j as highlightAllFeatures } from "../../chunks/mapViewUtils.js";
import { d as queryFeaturesByGeometry } from "../../chunks/queryUtils.js";
import { u as useT9n } from "../../chunks/useT9n.js";
import { createRef, ref } from "lit-html/directives/ref.js";
import { LitElement, createEvent, noShadowRoot, safeClassMap } from "@arcgis/lumina";
import { css, html } from "lit";
import { useContextConsumer } from "@arcgis/lumina/context";
import { p as pnContext } from "../../chunks/publicNotificationContext.js";
import Graphic from "@arcgis/core/Graphic";
import GraphicsLayer from "@arcgis/core/layers/GraphicsLayer";
const styles = css`@layer{
/** @license
 * Copyright 2025 Esri
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

:host {
  display: block;
}

.div-not-visible {
  display: none !important;
}

.border {
  outline: 1px solid var(--calcite-color-border-input);
}

/* COPY FROM JS */
.esri-sketch {
  display: flex;
  flex-flow: column wrap;
}

.esri-widget {
  box-sizing: border-box;
  color: #323232;
  font-size: 14px;
  font-family: 'Avenir Next', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  line-height: 1.3em;
  background-color: var(--calcite-color-foreground-1);
}

/* DIV CHILD */
.esri-sketch__panel {
  align-items: center;
  display: flex;
  flex-flow: row nowrap;
  padding: 0;
}

/* DIV CHILD CHILD */
.esri-sketch__tool-section {
  border-right: 1px solid rgba(110, 110, 110, 0.3);
}

.esri-sketch__section {
  align-items: center;
  display: flex;
  flex-flow: row nowrap;
  padding: 0 7px;
  margin: 6px 0;
  border-right: 1px solid rgba(110, 110, 110, 0.3);
}

.display-flex {
  display: flex;
}

.font-bold {
  font-weight: bold;
}

.width-full {
  width: 100%;
}

.label-margin-0 {
  --calcite-label-margin-bottom: 0;
}

.padding-start-1-2 {
  padding-inline-start: 0.5rem;
}

.font-weight-500 {
  font-weight: 500;
}

.word-wrap-anywhere {
  word-wrap: anywhere;
}

.tooltip-message {
  padding: 5px 8px;
  font-weight: var(--calcite-font-weight-normal);
  color: var(--calcite-color-text-2);
  max-width: 400px;
}
}`;
class RefineSelection extends LitElement {
  constructor() {
    super();
    this.enabledLayerIds = [];
    this.enableSearchDistance = true;
    this.enableSearchDistanceOnLoad = false;
    this.searchDistanceEnabled = false;
    this.selectionSets = [];
    this.bufferColor = [227, 139, 79, 0.8];
    this.bufferOutlineColor = [255, 255, 255];
    this.geometries = [];
    this.drawnGraphicsArr = [];
    this._translations = useT9n({ name: "refine-selection", blocking: true });
    this._selectionMode = "ADD";
    this._addEnabled = true;
    this._drawTools = createRef();
    this._enabledLayerIds = [];
    this._layerPicker = createRef();
    this._featuresCollection = {};
    this._pnContextConsumer = useContextConsumer({
      context: pnContext,
      subscribe: true
    });
    this._bufferTools = createRef();
    this._undoGraphicsArr = [];
    this.selectionLoadingChange = createEvent();
    this.selectionSetsChanged = createEvent();
    this.listenOn(window, "distanceChanged", this.distanceChanged);
    this.listenOn(window, "unitChanged", this.unitChanged);
  }
  static {
    this.properties = { addresseeLayer: [0, {}, { attribute: false }], enabledLayerIds: [0, {}, { attribute: false }], enableSearchDistance: [5, {}, { type: Boolean }], enableSearchDistanceOnLoad: [5, {}, { type: Boolean }], mapView: [0, {}, { attribute: false }], searchDistanceEnabled: [5, {}, { type: Boolean }], selectionSets: [0, {}, { attribute: false }], sketchLineSymbol: [0, {}, { attribute: false }], sketchPointSymbol: [0, {}, { attribute: false }], sketchPolygonSymbol: [0, {}, { attribute: false }], defaultBufferUnit: 1, bufferColor: 1, bufferOutlineColor: 1, defaultBufferDistance: [9, {}, { type: Number }], geometries: [0, {}, { attribute: false }], drawnGraphicsArr: [0, {}, { attribute: false }], _translations: [16, {}, { state: true }], _selectionMode: [16, {}, { state: true }], _refineLayer: [16, {}, { state: true }] };
  }
  static {
    this.styles = styles;
  }
  static {
    this.shadowRootOptions = noShadowRoot;
  }
  willUpdate(changes) {
    if (changes.has("defaultBufferUnit") && this.hasUpdated && this._refineSelectionSet) {
      this._refineSelectionSet.unit = this.defaultBufferUnit;
    }
    if (changes.has("defaultBufferDistance") && this.hasUpdated && this._refineSelectionSet) {
      this._refineSelectionSet.distance = this.defaultBufferDistance;
    }
  }
  async distanceChanged(event) {
    if (event.detail.newValue !== event.detail.oldValue && this._refineSelectionSet) {
      this._refineSelectionSet.distance = event.detail.newValue;
    }
  }
  async unitChanged(event) {
    if (event.detail.newValue !== event.detail.oldValue && this._refineSelectionSet) {
      this._refineSelectionSet.unit = event.detail.newValue;
    }
  }
  async load() {
    this._enabledLayerIds = this._getEnabledLayerIds();
    await this._setRefineSet(this._enabledLayerIds[0]);
    this._undoGraphicsArr = this._refineSelectionSet?.undoGraphicsArr;
  }
  async loaded() {
    await this._init();
  }
  render() {
    const layerPickerClass = this._enabledLayerIds.length > 1 ? "display-block" : "display-none";
    return html`<div class=${`${layerPickerClass} padding-top-sides-1`}><div class="display-flex"><calcite-label class="font-bold width-full label-margin-0"><div class="display-flex">${this._translations.inputLayer}<calcite-icon class="padding-start-1-2 icon" .flipRtl=${!(this._translations._lang?.toLowerCase() === "he")} icon=question id=refine-input-layer scale=s></calcite-icon></div><map-layer-picker .enabledLayerIds=${this._enabledLayerIds} .mapView=${this.mapView} @layerSelectionChange=${(_evt) => {
      void this._layerSelectionChange(_evt);
    }} .selectedIds=${this._refineLayer ? [this._refineLayer.layer.id] : []} ${ref(this._layerPicker)}></map-layer-picker></calcite-label><calcite-popover closable label overlay-positioning=fixed reference-element=refine-input-layer><span class="tooltip-message">${this._translations.inputLayerTip}</span></calcite-popover></div></div><div class="padding-1"><div class="padding-bottom-1"><calcite-segmented-control class="w-100" width=full><calcite-segmented-control-item .checked=${this._addEnabled} class="w-50 word-wrap-anywhere" @click=${() => this._setSelectionMode("ADD")} value=ADD><span class="font-weight-500">${this._translations.add}</span></calcite-segmented-control-item><calcite-segmented-control-item .checked=${!this._addEnabled} class="w-50 word-wrap-anywhere" @click=${() => this._setSelectionMode("REMOVE")} value=REMOVE><span class="font-weight-500">${this._translations.remove}</span></calcite-segmented-control-item></calcite-segmented-control></div><div><map-draw-tools active draw-mode=REFINE .mapView=${this.mapView} @drawRedo=${() => this._redo()} @drawUndo=${() => this._undo()} @sketchGraphicsChange=${this._sketchGraphicsChanged} .pointSymbol=${this.sketchPointSymbol} .polygonSymbol=${this.sketchPolygonSymbol} .polylineSymbol=${this.sketchLineSymbol} .redoEnabled=${this._refineSelectionSet?.redoStack && this._refineSelectionSet.redoStack.length > 0} .undoEnabled=${this._refineSelectionSet?.undoStack && this._refineSelectionSet.undoStack.length > 0} ${ref(this._drawTools)}></map-draw-tools></div>${this.enableSearchDistance ? this._getBufferOptions() : void 0}<br>${html`<calcite-list class="list-border" label>${this._getRefineSelectionSetList()}</calcite-list>`}</div>`;
  }
  async _init() {
    this._initGraphicsLayer();
  }
  _initGraphicsLayer() {
    const title = this._translations.bufferLayer;
    if (this.mapView) {
      const bufferIndex = this.mapView.map.layers.findIndex((l) => l.title === title);
      if (bufferIndex > -1) {
        this._bufferGraphicsLayer = this.mapView.map.layers.getItemAt(bufferIndex);
      } else {
        this._bufferGraphicsLayer = new GraphicsLayer({ title, listMode: "hide" });
        if (this._bufferGraphicsLayer) {
          const sketchIndex = this.mapView.map.layers.findIndex((l) => l.title === this._translations.sketchLayer);
          if (sketchIndex > -1) {
            this.mapView.map.layers.add(this._bufferGraphicsLayer, sketchIndex);
          } else {
            this.mapView.map.layers.add(this._bufferGraphicsLayer);
          }
        }
      }
    }
  }
  _layerSelectionChange(_evt) {
    const id = _evt.detail[0];
    void this._setRefineSet(id);
  }
  _setSelectionMode(selectionMode) {
    this._selectionMode = selectionMode;
  }
  async _sketchGraphicsChanged(_evt) {
    const graphics = _evt.detail?.graphics[0];
    const geom = graphics.geometry;
    this.geometries = [geom];
    const oids = await this._selectFeatures(geom);
    this._sketchGraphics = graphics;
    if (this._refineSelectionSet?.distance === 0 && oids.length > 0) {
      const obj = { drawnGraphics: graphics, bufferGraphics: void 0 };
      this.drawnGraphicsArr.push(obj);
    }
  }
  _getEnabledLayerIds() {
    return this.selectionSets.reduce((prev, cur) => {
      const id = cur?.layerView?.layer.id;
      if (id && prev.indexOf(id) < 0) {
        prev.push(id);
      } else if (cur.workflowType === "REFINE") {
        Object.keys(cur.refineInfos).forEach((k) => {
          if (prev.indexOf(k) < 0) {
            prev.push(k);
          }
        });
      }
      return prev;
    }, []);
  }
  async _setRefineSet(id) {
    if (!this.selectionSets.some((ss) => {
      if (ss.workflowType === "REFINE") {
        this._refineSelectionSet = ss;
        return Object.keys(ss.refineInfos).indexOf(id) > -1;
      } else {
        return false;
      }
    })) {
      await this._initRefineSet(id, this._refineSelectionSet);
    }
    if (this._refineSelectionSet) {
      this._refineLayer = this._refineSelectionSet.refineInfos[id].layerView;
    }
  }
  async _initRefineSet(id, selectionSet) {
    const refineInfo = {};
    refineInfo[id] = {
      addIds: [],
      removeIds: [],
      layerView: this.mapView && await getFeatureLayerView(this.mapView, id)
    };
    if (selectionSet) {
      selectionSet.refineInfos = { ...selectionSet.refineInfos, ...refineInfo };
    } else {
      this._refineSelectionSet = {
        id: Date.now(),
        searchResult: void 0,
        buffer: void 0,
        distance: this.defaultBufferDistance || 0,
        download: true,
        unit: this.defaultBufferUnit || "feet",
        label: "Refine",
        selectedIds: [],
        layerView: this.mapView && await getFeatureLayerView(this.mapView, id),
        geometries: [],
        graphics: [],
        selectLayers: [],
        workflowType: "REFINE",
        searchDistanceEnabled: false,
        useLayerFeaturesEnabled: false,
        refineInfos: refineInfo,
        redoStack: [],
        undoStack: [],
        sketchGraphic: void 0,
        undoGraphicsArr: []
      };
      this.selectionSets.push(this._refineSelectionSet);
    }
  }
  _undo() {
    if (this._refineSelectionSet) {
      const undoOp = this._refineSelectionSet.undoStack && this._refineSelectionSet.undoStack.pop();
      if (undoOp) {
        if (this.drawnGraphicsArr.length > 0) {
          const graphics = this.drawnGraphicsArr.pop();
          if (graphics) {
            this._refineSelectionSet.undoGraphicsArr?.push(graphics);
          }
          this._undoGraphicsArr.push(graphics);
        }
        this._refineSelectionSet.redoStack && void this._updateIds(undoOp.ids, undoOp.mode === "ADD" ? "REMOVE" : "ADD", this._refineSelectionSet.redoStack, undoOp.layerView);
      }
    }
  }
  _redo() {
    if (this._refineSelectionSet) {
      const redoOp = this._refineSelectionSet.redoStack && this._refineSelectionSet.redoStack.pop();
      if (redoOp) {
        if (this._undoGraphicsArr.length > 0) {
          const graphics = this._undoGraphicsArr.pop();
          this._refineSelectionSet.undoGraphicsArr?.pop();
          if (graphics) {
            this.drawnGraphicsArr.push(graphics);
          }
        }
        this._refineSelectionSet.undoStack && void this._updateIds(redoOp.ids, redoOp.mode === "ADD" ? "REMOVE" : "ADD", this._refineSelectionSet.undoStack, redoOp.layerView);
      }
    }
  }
  _getBufferOptions() {
    if (this.enableSearchDistanceOnLoad && this._refineSelectionSet) {
      this._refineSelectionSet.searchDistanceEnabled = true;
      this.searchDistanceEnabled = true;
      this.enableSearchDistanceOnLoad = false;
    }
    const showBufferToolsClass = this._refineSelectionSet?.searchDistanceEnabled ? "search-distance" : "div-not-visible";
    return html`<div><div class="padding-top-1 display-flex"><calcite-label class="label-margin-0 w-100" layout=inline-space-between><div class="tooltip-container">${this._translations.searchDistance}<calcite-icon class="padding-start-1-2 icon" .flipRtl=${!(this._translations._lang?.toLowerCase() === "he")} icon=question id=search-distance-icon scale=s></calcite-icon></div></calcite-label><calcite-popover closable label overlay-positioning=fixed reference-element=search-distance-icon><span class="tooltip-message">${this._translations.useSearchDistanceTootip}</span></calcite-popover><calcite-switch .checked=${this._refineSelectionSet?.searchDistanceEnabled} @calciteSwitchChange=${() => {
      this.searchDistanceEnabled = !this.searchDistanceEnabled;
      if (this._refineSelectionSet) {
        this._refineSelectionSet.searchDistanceEnabled = this.searchDistanceEnabled;
      }
    }}></calcite-switch></div><div class=${safeClassMap(showBufferToolsClass)}><buffer-tools .disabled=${!this.searchDistanceEnabled} .distance=${this._refineSelectionSet?.distance} .geometries=${this.geometries} @bufferComplete=${(_evt) => void this._bufferComplete(_evt)} .unit=${this._refineSelectionSet?.unit} ${ref(this._bufferTools)}></buffer-tools></div></div>`;
  }
  async _bufferComplete(_evt) {
    this._bufferGeometry = Array.isArray(_evt.detail) ? _evt.detail[0] : _evt.detail;
    if (this._bufferGeometry) {
      const symbol = {
        type: "simple-fill",
        color: this.bufferColor,
        outline: {
          color: this.bufferOutlineColor,
          width: 1
        }
      };
      const polygonGraphic = new Graphic({
        geometry: this._bufferGeometry,
        symbol
      });
      if (this._bufferGraphicsLayer && polygonGraphic && this.mapView) {
        this._bufferGraphicsLayer.removeAll();
        this._bufferGraphicsLayer.add(polygonGraphic);
        const oids = await this._selectFeatures(this._bufferGeometry);
        if (oids.length > 0) {
          const obj = { drawnGraphics: this._sketchGraphics, bufferGraphics: polygonGraphic };
          this.drawnGraphicsArr.push(obj);
        }
      }
    } else {
      if (this._bufferGraphicsLayer) {
        this._bufferGraphicsLayer.removeAll();
      }
    }
  }
  _getRefineSelectionSetList() {
    const total = this._getTotal(this.selectionSets);
    let refineSet;
    this.selectionSets.some((ss) => {
      if (ss.workflowType === "REFINE") {
        refineSet = ss;
        return true;
      } else {
        return false;
      }
    });
    let numAdded = 0;
    let numRemoved = 0;
    refineSet?.refineInfos && Object.keys(refineSet.refineInfos).forEach((k) => {
      numAdded += refineSet.refineInfos[k].addIds.length;
      numRemoved += refineSet.refineInfos[k].removeIds.length;
    });
    const added = this._translations.featuresAdded;
    const removed = this._translations.featuresRemoved;
    const selected = this._translations.totalSelected;
    return [
      html`<calcite-list-item .label=${added.replace("{{n}}", numAdded.toString())}></calcite-list-item>`,
      html`<calcite-list-item .label=${removed.replace("{{n}}", numRemoved.toString())}></calcite-list-item>`,
      html`<calcite-list-item .label=${selected.replace("{{n}}", total.toString())}></calcite-list-item>`
    ];
  }
  _getTotal(selectionSets) {
    const idSets = getIdSets(selectionSets);
    return Object.keys(idSets).reduce((prev, cur) => {
      const idSet = idSets[cur];
      prev += idSet.ids.length;
      return prev;
    }, 0);
  }
  async _selectFeatures(geom) {
    this.selectionLoadingChange.emit(true);
    let oids = [];
    if (this._refineLayer) {
      this._featuresCollection[this._refineLayer?.layer.id] = [];
      const response = await queryFeaturesByGeometry(0, this._refineLayer?.layer, geom, this._featuresCollection);
      this.selectionLoadingChange.emit(false);
      let graphics = [];
      Object.keys(response).forEach((k) => {
        if (k === this._refineLayer?.layer.id) {
          graphics = graphics.concat(response[k]);
        }
      });
      oids = Array.isArray(graphics) ? graphics.map((g) => g.attributes[g?.layer?.objectIdField]) : [];
      this._refineSelectionSet?.undoStack && await this._updateIds(oids, this._selectionMode, this._refineSelectionSet.undoStack, this._refineLayer);
      if (this._bufferGraphicsLayer && this._refineSelectionSet && this._refineSelectionSet.distance > 0) {
        await new Promise((resolve) => setTimeout(resolve, 1e3));
        this._bufferGraphicsLayer.removeAll();
      }
      this.geometries = [];
      this._drawTools.value && void this._drawTools.value.clear();
    }
    return oids;
  }
  async _highlightFeatures() {
    const _state = this._pnContextConsumer.value;
    _state.removeHandles();
    _state.highlightHandles = await highlightAllFeatures(this.selectionSets);
  }
  async _updateIds(ids, mode, operationStack, layerView) {
    let selectionSetsChanged = false;
    const refineInfos = this._refineSelectionSet?.refineInfos;
    const layerId = layerView.layer.id;
    const newRefineInfo = {};
    newRefineInfo[layerId] = {
      addIds: [],
      removeIds: [],
      layerView
    };
    const idUpdates = refineInfos && Object.keys(refineInfos).indexOf(layerId) > -1 ? refineInfos[layerId] : newRefineInfo[layerId];
    if (mode === "ADD") {
      idUpdates.addIds = [.../* @__PURE__ */ new Set([...ids, ...idUpdates.addIds])];
      if (idUpdates.addIds.length > 0) {
        operationStack.push({
          ids,
          mode,
          layerView
        });
      }
      if (idUpdates.removeIds.length > 0) {
        idUpdates.removeIds = idUpdates.removeIds.filter((id) => ids.indexOf(id) < 0);
      }
    } else {
      const validIds = this.selectionSets.reduce((prev, cur) => {
        ids.forEach((id) => {
          if (cur.workflowType !== "REFINE") {
            if (cur.selectedIds.indexOf(id) > -1) {
              prev.push(id);
            }
          } else {
            Object.keys(cur.refineInfos).some((k) => {
              const refineInfo = cur.refineInfos[k];
              if (refineInfo.layerView.layer.id === layerView.layer.id && refineInfo.addIds.indexOf(id) > -1) {
                prev.push(id);
                return true;
              } else {
                return false;
              }
            });
          }
        });
        return prev;
      }, []);
      idUpdates.removeIds = [.../* @__PURE__ */ new Set([...validIds, ...idUpdates.removeIds])];
      idUpdates.addIds = idUpdates.addIds.filter((id) => validIds.indexOf(id) < 0);
      if (idUpdates.removeIds.length > 0) {
        operationStack.push({
          ids: validIds,
          mode,
          layerView
        });
      }
      this.selectionSets = this.selectionSets.reduce((prev, cur) => {
        if (cur.workflowType !== "REFINE" && cur.layerView.layer.id === layerView.layer.id) {
          cur.selectedIds = cur.selectedIds.filter((id) => idUpdates.removeIds.indexOf(id) < 0);
          if (cur.selectedIds.length > 0) {
            prev.push(cur);
          } else {
            selectionSetsChanged = true;
          }
        } else {
          prev.push(cur);
        }
        return prev;
      }, []);
    }
    if (this._refineSelectionSet) {
      this._refineSelectionSet.refineInfos[layerId] = idUpdates;
    }
    this.selectionSets = [...this.selectionSets];
    if (selectionSetsChanged) {
      this.selectionSetsChanged.emit(this.selectionSets);
    }
    await this._highlightFeatures();
  }
}
customElement("refine-selection", RefineSelection);
export {
  RefineSelection
};
