/* COPYRIGHT Esri - https://js.arcgis.com/5.2/LICENSE.txt */
import { forceInteractive as _ } from "@arcgis/core/applications/Components/analysisUtils.js";
import f from "@arcgis/core/core/Accessor.js";
import { property as o, subclass as V } from "@arcgis/core/core/accessorSupport/decorators.js";
import { ignoreAbortErrors as v } from "@arcgis/core/core/promiseUtils.js";
import { when as m, watch as w, on as A, whenOnce as g } from "@arcgis/core/core/reactiveUtils.js";
import { log as p } from "@arcgis/toolkit/log";
import { c as u, t as O, i as I, a as b } from "./async-utils.js";
import { a as h } from "./maybe.js";
import { getDefaultUnitForView as F } from "@arcgis/core/applications/Components/getDefaultUnits.js";
var T = Object.defineProperty, R = Object.getOwnPropertyDescriptor, n = (e, s, t, a) => {
  for (var r = a > 1 ? void 0 : a ? R(s, t) : s, l = e.length - 1, c; l >= 0; l--)
    (c = e[l]) && (r = (a ? c(s, t, r) : c(r)) || r);
  return a && r && T(s, t, r), r;
};
const y = /* @__PURE__ */ Symbol("interactiveHandle");
let i = class extends f {
  // #region Lifecycle
  // Intentionally keep constructor side-effect free: callers may set properties in any order after instantiation.
  constructor() {
    super({}), this.operationState = "inactive", this._ownsAnalysis = !1, this.shouldForceInteractive = !0, this._changeFromReconnect = !1, this._userOperationInfo = null, this._loggedUnsupportedErrorMessage = !1;
  }
  initialize() {
    this._set("analysis", this.constructAnalysis()), this._ownsAnalysis = !0;
    const e = () => {
      !this._changeFromReconnect && !this._viewHasAnalysis && (this._ownsAnalysis = !1);
      const s = !this._changeFromReconnect;
      this._changeFromReconnect = !1, s && this._scheduleViewReconnect();
    };
    this.addHandles([
      m(
        () => this.view?.ready && !this.supported,
        () => {
          this._loggedUnsupportedErrorMessage || p("error", this, this.unsupportedErrorMessage);
        },
        { sync: !0, initial: !0 }
      ),
      w(() => [this.analysis, this._viewHasAnalysis], e, { sync: !0 }),
      A(
        () => this.view,
        "analysis-view-destroy",
        (s) => {
          s.analysis === this.analysis && e();
        }
      ),
      w(
        () => ({
          view: this.view,
          ready: !!this.view?.ready,
          supported: this.supported
        }),
        ({ view: s }, t) => {
          const a = t?.view;
          s !== a && (this._userOperationInfo = h(this._userOperationInfo), this._disconnectFromView(a)), this._scheduleViewReconnect();
        },
        { sync: !0, initial: !0 }
      )
    ]);
  }
  destroy() {
    this._reconnectViewTask = h(this._reconnectViewTask), this._userOperationInfo = h(this._userOperationInfo), this.analysisView != null && (this.analysisView.visible = void 0), this._disconnectFromView(this.view), this._set("view", null), this._ownsAnalysis && this.analysis?.destroy();
  }
  get defaultMeasurementSystem() {
    return this.view?.ready ? F(this.view) : "metric";
  }
  get active() {
    return this._userOperationInfo?.state === "running";
  }
  set analysis(e) {
    e !== this._get("analysis") && (this._userOperationInfo = h(this._userOperationInfo), this._disconnectFromView(this.view), this._setExternalAnalysis(e), this._scheduleViewReconnect());
  }
  get connectingToView() {
    return !!this._reconnectViewTask;
  }
  get disabled() {
    return !this.view?.ready || !this.supported;
  }
  set hideVisualization(e) {
    this._set("hideVisualization", e), this.analysisView && (this.analysisView.visible = !e);
  }
  get ready() {
    return !!this.analysisView && !this.connectingToView;
  }
  get supported() {
    return !this.view || this.supportedViewType === "both" || this.view.type === this.supportedViewType;
  }
  get _viewHasAnalysis() {
    const { view: e } = this;
    return e?.analyses.includes(this.analysis) === !0;
  }
  // #endregion
  // #region Public Methods
  /**
   * Reset analysis inputs and cancel any active user operation.
   */
  clear() {
    this._userOperationInfo = h(this._userOperationInfo), this.clearAnalysis();
  }
  /**
   * Start the user operation.
   *
   * If the required analysis inputs are missing, this calls `place()` once the view is ready. You can provide a custom
   * `operation` to override the default behavior. Set `clear: false` to retain existing analysis inputs.
   */
  async start(e) {
    if (this.hideVisualization) {
      p("warn", this, "Cannot start analysis when not visible");
      return;
    }
    this.stop(), e?.clear !== !1 && this.clear();
    const s = {
      task: null,
      abort: null,
      state: "pending"
    }, t = u(async (a) => {
      if (s.state = "wait-for-view-ready", await g(() => this.ready, a), s.state = "running", !this.analysisView || !this.view)
        return;
      this.operationState = "active";
      const r = e?.operation?.({ signal: a }) ?? this.place({ signal: a });
      await v(r);
    });
    return t.promise.finally(() => {
      (this._userOperationInfo === s || !this._userOperationInfo) && (this.operationState = "inactive");
    }), s.task = t, s.abort = () => t.abort(), this._userOperationInfo = s, await t.promise;
  }
  /**
   * Stop the active user operation, if any.
   */
  stop() {
    this._userOperationInfo = h(this._userOperationInfo);
  }
  // #endregion
  // #region Private/Protected Methods
  /**
   * Define the interactive placement workflow for the analysis.
   * Implement in subclasses to collect required inputs. Honor `AbortSignal`.
   */
  place(e) {
    throw new Error("place() not implemented for this analysis view model");
  }
  /**
   * Hook for subclasses to clear analysis inputs when `clear()` is called.
   */
  clearAnalysis() {
  }
  /**
   * Hook for subclasses managing an analysis that belongs to a layer.
   * Called when the view is ready and the `analysisView` is created.
   */
  onConnectToAnalysisView(e) {
  }
  /**
   * Hook for subclasses to react when the view becomes unready and the
   * internal analysis is removed from the map/analyses.
   */
  onDisconnectFromAnalysisView() {
  }
  _scheduleViewReconnect() {
    this._reconnectViewTask = h(this._reconnectViewTask);
    const e = u(async (s) => {
      try {
        await this._reconnectView(s);
      } catch (t) {
        if (O(s), !I(t)) {
          p("warn", this, `Failed to use analysis in view model. ${String(t)}`);
          return;
        }
        throw t;
      } finally {
        e === this._reconnectViewTask && (this._reconnectViewTask = void 0);
      }
    });
    this._reconnectViewTask = e;
  }
  /**
   * Reconnect the analysis to the current view, obtaining an `analysisView` when supported and ready.
   * Aborts active operations that are past the "waiting for view" phase.
   */
  async _reconnectView(e) {
    const { view: s } = this, t = s?.ready && this.supported, a = this.analysis;
    if (this._userOperationInfo = d(this._userOperationInfo), this._disconnectFromView(s), !t || !s || !a)
      return;
    this._ownsAnalysis && (this._changeFromReconnect = !0, s.analyses.add(a));
    const r = await s.whenAnalysisView(a);
    if (this.analysisView = r, b(e)) {
      this._userOperationInfo = d(this._userOperationInfo);
      return;
    }
    r.visible = !this.hideVisualization, this.shouldForceInteractive && this.addHandles(_(r), y), this.onConnectToAnalysisView(r);
  }
  /**
   * Disconnect the analysis from the given view.
   */
  _disconnectFromView(e) {
    this._ownsAnalysis && e?.analyses.includes(this.analysis) && (this._changeFromReconnect = !0, this.clearAnalysis(), e.analyses.remove(this.analysis)), this.onDisconnectFromAnalysisView(), this.removeHandles(y), this.analysisView = void 0;
  }
  /**
   * Set an externally owned analysis.
   */
  _setExternalAnalysis(e) {
    this.analysisView && !this._ownsAnalysis && (this.analysisView.visible = void 0, this.removeHandles(y)), this.analysisView = void 0, this._ownsAnalysis = !1, this._set("analysis", e), this._changeFromReconnect = !1;
  }
  // #endregion
};
n([
  o()
], i.prototype, "defaultMeasurementSystem", 1);
n([
  o()
], i.prototype, "active", 1);
n([
  o()
], i.prototype, "analysis", 1);
n([
  o()
], i.prototype, "connectingToView", 1);
n([
  o()
], i.prototype, "disabled", 1);
n([
  o()
], i.prototype, "hideVisualization", 1);
n([
  o()
], i.prototype, "operationState", 2);
n([
  o()
], i.prototype, "ready", 1);
n([
  o()
], i.prototype, "supported", 1);
n([
  o()
], i.prototype, "view", 2);
n([
  o()
], i.prototype, "_ownsAnalysis", 2);
n([
  o()
], i.prototype, "_viewHasAnalysis", 1);
n([
  o()
], i.prototype, "_reconnectViewTask", 2);
n([
  o()
], i.prototype, "analysisView", 2);
n([
  o()
], i.prototype, "shouldForceInteractive", 2);
i = n([
  V("esri.components.support.AnalysisViewModel")
], i);
function d(e) {
  return e?.state === "running" ? (e.abort(), null) : e;
}
export {
  i as A
};
