import type Graphic from "../../Graphic.js";
import type Point from "../../geometry/Point.js";
import type UtilityNetwork from "../../networks/UtilityNetwork.js";
import type TerminalConfiguration from "../../networks/support/TerminalConfiguration.js";
import type NetworkElement from "../../rest/networks/support/NetworkElement.js";
import type TraceParameters from "../../rest/networks/support/TraceParameters.js";
import type TraceResult from "../../rest/networks/support/TraceResult.js";
import type PictureMarkerSymbol from "../../symbols/PictureMarkerSymbol.js";
import type SimpleMarkerSymbol from "../../symbols/SimpleMarkerSymbol.js";
import type MapView from "../../views/MapView.js";
import type { EventedAccessor } from "../../core/Evented.js";
import type { NetworkSourceJSON } from "../../networks/support/jsonTypes.js";
import type { NamedTraceConfigurationProperties } from "../../networks/support/NamedTraceConfiguration.js";
import type { TraceLocationType } from "../../networks/support/typeUtils.js";
import type { FeatureSetInfo } from "../../networks/support/utils.js";
import type { TraceLocationProperties } from "../../rest/networks/support/TraceLocation.js";
import type { GoToTarget2D, GoToTarget3D } from "../../views/types.js";
import type { CreateEvent } from "../Sketch/types.js";
import type { ResultAreaProperties } from "./types.js";

export interface UtilityNetworkTraceViewModelProperties extends Partial<Pick<UtilityNetworkTraceViewModel, "defaultGraphicColor" | "enableResultArea" | "flags" | "resultAreaProperties" | "selectedTraces" | "selectOnComplete" | "showGraphicsOnComplete" | "showSelectionAttributes" | "traceResults" | "utilityNetwork" | "view">> {}

export type UtilityNetworkTraceViewModelState = "ready" | "loading";

/** TraceItem extends the named trace configuration and adds a property to manage the selection on the view. */
export interface TraceItem extends NamedTraceConfigurationProperties {
  /** Returns `true` if there is a selection on the view for a trace. */
  selected?: boolean;
}

/** DisplayField represents the attribute field used as a display label for flags and selected features. */
export interface DisplayField {
  /** The feature's display field. */
  field?: string | null;
  /** The value of the field. */
  value: string;
}

/** FlagProperty represents the properties to define each flag point (starting points and barriers). */
export interface FlagProperty extends TraceLocationProperties {
  /**
   * The flag type being set. Must be `"starting point"`, `"stopping point"` or `"barrier"`.
   *
   * **Possible Values**
   *
   * Value | Description |
   * ----- | ----------- |
   * starting-point | The flag set will be the starting location of the trace.
   * stopping-point | The flag set will be the stopping location of the trace.
   * barrier | The flag set will mark the location to stop the trace.
   */
  type: TraceLocationType;
  /** The available [terminals](https://developers.arcgis.com/javascript/latest/references/core/networks/support/Terminal/) to define the permissible paths based on the terminal configurations. The default terminal is always set. */
  allTerminals?: TerminalConfiguration | null;
  /** The terminals that are selected for the flag (this can be the default terminal or terminals selected by the end-user). */
  selectedTerminals?: Array<number> | null;
  /** The display field of the flag. */
  displayValue?: DisplayField | null;
  /** The geometry point of the flag. */
  mapPoint?: Point | null;
  /** All the information returned by the hitTest. */
  details?: any | null;
  /** The flag graphic. */
  mapGraphic?: Graphic | null;
  /** The id of the flag. */
  id?: number | null;
}

/** GraphicColor represents the color for the trace result graphic in the graphics layer. */
export interface GraphicColor {
  /** The color of the trace result graphic in the view. */
  color: [
      number,
      number,
      number,
      number
  ];
  /** The opacity of the graphic symbol's halo. */
  haloOpacity: number;
  /** The color of the trace result graphic in the color picker. */
  hex: string;
}

/** ResultAreaPropertiesExtend represents the properties to determine the size and color of the result area convex hull or buffer, and whether it displays on the map when the trace completes. */
export interface ResultAreaPropertiesExtend extends ResultAreaProperties {
  /** Determines if the area is shown on the map. */
  show: boolean;
}

/** TraceResultExtend organizes the results based on the trace configuration and the trace results. */
export interface TraceResultExtend {
  /** TraceItem extends the named trace configuration and adds a property to manage the selection on the view. */
  trace: TraceItem;
  /** The collection of results returned from the trace. */
  results: TraceResult | null;
  /** Returns true if selection is enabled. */
  selectionEnabled: boolean;
  /** Returns true if graphic is enabled. */
  graphicEnabled: boolean;
  /** The color for the graphic of the trace results in the graphics layer. */
  graphicColor: GraphicColor;
  /** The current status of the trace to return errors from the server. */
  status: string;
}

/** ValidSetup verifies whether a trace meets all the requirements before it can execute. */
export interface ValidSetup {
  /** Is `true` if the requirements are met. */
  status: boolean;
  /** An array of error messages for the missing requirements. */
  issues: string[];
}

export interface UtilityNetworkTraceViewModelEvents {
  /**
   * Fires when a flag point graphic is added to the map.
   *
   * @since 4.23
   */
  "add-flag-complete": UtilityNetworkTraceViewModelAddFlagCompleteEvent;
  /**
   * Fires when adding a flag point graphic to the map fails.
   *
   * @since 4.23
   */
  "add-flag-error": UtilityNetworkTraceViewModelAddFlagErrorEvent;
  /**
   * Fires when the button to add either a starting point or barrier is clicked.
   *
   * @since 4.23
   */
  "add-flag": UtilityNetworkTraceViewModelAddFlagEvent;
  /**
   * Fires when adding a result area graphic to the map.
   *
   * @since 4.28
   */
  "add-result-area": UtilityNetworkTraceViewModelAddResultAreaEvent;
  /**
   * Fires after a trace when [UtilityNetworkTrace.enableResultArea](https://developers.arcgis.com/javascript/latest/references/core/widgets/UtilityNetworkTrace/#enableResultArea) is true.
   *
   * @since 4.29
   */
  "create-result-area": UtilityNetworkTraceViewModelCreateResultAreaEvent;
  /**
   * Fires when removing a result area graphic from the map.
   *
   * @since 4.28
   */
  "remove-result-area": UtilityNetworkTraceViewModelRemoveResultAreaEvent;
}

export interface UtilityNetworkTraceViewModelAddFlagCompleteEvent {
  /** The type of flag added. */
  type: TraceLocationType;
  /** The symbol of the flag point graphic. */
  symbol?: SimpleMarkerSymbol | PictureMarkerSymbol | null;
}

export interface UtilityNetworkTraceViewModelAddFlagErrorEvent {
  /** The type of flag added. */
  type: TraceLocationType;
  /** The symbol of the flag point graphic. */
  symbol?: SimpleMarkerSymbol | PictureMarkerSymbol | null;
}

export interface UtilityNetworkTraceViewModelAddFlagEvent {
  /** The type of flag added. */
  type: TraceLocationType;
}

export interface UtilityNetworkTraceViewModelAddResultAreaEvent {
  /** The graphic of the result area generated from the trace. */
  graphic: Graphic;
}

export interface UtilityNetworkTraceViewModelCreateResultAreaEvent {
  /** The graphic of the result area generated from the trace if [UtilityNetworkTrace.enableResultArea](https://developers.arcgis.com/javascript/latest/references/core/widgets/UtilityNetworkTrace/#enableResultArea) is true. */
  graphic?: Graphic | Graphic[];
}

export interface UtilityNetworkTraceViewModelRemoveResultAreaEvent {
  /** The removed graphic of the result area generated from the trace. */
  graphic?: Graphic | Graphic[];
}

/**
 * Provides the logic for the [UtilityNetworkTrace](https://developers.arcgis.com/javascript/latest/references/core/widgets/UtilityNetworkTrace/) widget and [component](https://developers.arcgis.com/javascript/latest/references/map-components/components/arcgis-utility-network-trace/).
 *
 * @deprecated since version 5.0. Use [UtilityNetworkTraceAnalysis](https://developers.arcgis.com/javascript/latest/references/core/networks/UtilityNetworkTraceAnalysis/).
 * @since 4.22
 * @see [UtilityNetworkTrace](https://developers.arcgis.com/javascript/latest/references/core/widgets/UtilityNetworkTrace/) widget
 * @see [Utility Network Trace component](https://developers.arcgis.com/javascript/latest/references/map-components/components/arcgis-utility-network-trace/)
 * @see [UtilityNetwork](https://developers.arcgis.com/javascript/latest/references/core/networks/UtilityNetwork/)
 * @see [NamedTraceConfiguration](https://developers.arcgis.com/javascript/latest/references/core/networks/support/NamedTraceConfiguration/)
 * @see [Trace (Utility Network)](https://pro.arcgis.com/en/pro-app/latest/tool-reference/utility-networks/trace.htm)
 * @see [Programming patterns: Widget viewModel pattern](https://developers.arcgis.com/javascript/latest/programming-patterns/#widget-viewmodel-pattern)
 * @see [Sample - UtilityNetworkTrace widget](https://developers.arcgis.com/javascript/latest/sample-code/widgets-untrace/)
 */
export default class UtilityNetworkTraceViewModel extends EventedAccessor {
  constructor(properties?: UtilityNetworkTraceViewModelProperties);
  /**
   * The default color to assign the aggregated geometry of a trace result.
   *
   * @default
   * {
   * color: [255, 255, 0, 0.6],
   * haloOpacity: 0.9,
   * fillOpacity: 0.2,
   * hex: "#FFFF00"
   * }
   * @since 4.23
   */
  accessor defaultGraphicColor: GraphicColor;
  /**
   * When true, provides the ability to show the convex hull or buffer.
   *
   * @default false
   * @since 4.27
   */
  accessor enableResultArea: boolean;
  /**
   * An array of map points to load into the widget to lookup flags.
   *
   * @default []
   * @since 4.22
   * @example
   * const unt = new UtilityNetworkTrace({
   *  view: view,
   *  showSelectionAttributes: true,
   *  selectOnComplete: true,
   *  showGraphicsOnComplete: true,
   *  selectedTraces: ["{E8D545B8-596D-4656-BF5E-16C1D7CBEC9B}"],
   *  flags: [
   *    {
   *      type: "starting-point",
   *      mapPoint: {
   *        spatialReference: { latestWkid: 3857, wkid: 102100 },
   *        x: -9814829.166046409,
   *        y: 5127094.1017433
   *      }
   *    },
   *    {
   *      type: "barrier",
   *      mapPoint: {
   *      spatialReference: { latestWkid: 3857, wkid: 102100 },
   *        x: -9814828.449441982,
   *        y: 5127089.085566963
   *      }
   *    }
   *  ]
   * });
   */
  accessor flags: FlagProperty[];
  /**
   * The properties to determine the size and color of the result area convex hull or buffer, and determines if it displays on the map when the trace completes.
   *
   * @default
   * {
   *  type: "convexhull",
   *  distance: 10,
   *  unit: "meters",
   *  areaUnit: "square-meters",
   *  color: {
   *    color: [255, 165, 0, 0.5],
   *    haloOpacity: 0.9,
   *    fillOpacity: 0.2,
   *    hex: "#ffa500"
   *  },
   *  show: false
   * }
   * @since 4.27
   * @example
   * const unt = new UtilityNetworkTrace({
   *  un: un,
   *  view: view,
   *  enableResultArea: true,
   *  resultAreaProperties: {
   *    type: "buffer",
   *    distance: 10,
   *    unit: "feet",
   *    areaUnit: "square-feet",
   *    color: {
   *      color: [255, 165, 0, 0.5],
   *      haloOpacity: 0.9,
   *      fillOpacity: 0.2,
   *      hex: "#ffa500"
   *    },
   *    show: true
   *  }
   * });
   */
  accessor resultAreaProperties: ResultAreaPropertiesExtend;
  /**
   * An array of global Ids of traces to select on initial load.
   *
   * @default []
   * @since 4.22
   */
  accessor selectedTraces: string[];
  /**
   * When true, the utility network elements are selected in the view when traces are completed.
   *
   * @default true
   * @since 4.22
   */
  accessor selectOnComplete: boolean;
  /**
   * When true, a graphic layer is added to the view to highlight the utility network elements when traces are completed.
   *
   * @default true
   * @since 4.22
   */
  accessor showGraphicsOnComplete: boolean;
  /**
   * Determines whether to show the list of selected features from completed traces.
   *
   * @default true
   * @since 4.22
   */
  accessor showSelectionAttributes: boolean;
  /**
   * The view model's state.
   *
   * @default "ready"
   */
  get state(): UtilityNetworkTraceViewModelState;
  /**
   * Stores the result of completed traces.
   *
   * @since 4.27
   */
  accessor traceResults: Array<TraceResultExtend>;
  /**
   * Determines the utility network to use.
   *
   * @since 4.27
   */
  accessor utilityNetwork: UtilityNetwork | null | undefined;
  /** The view from which the widget will operate. */
  accessor view: MapView | null | undefined;
  /**
   * Adds a flag point graphic for the click event on the view if there is a feature to query.
   *
   * @param type - The type of flag can be a `"starting point"` or a `"barrier"`.
   * @returns When resolved, response is `true` if there is a feature to query in the view.
   */
  addFlagByHit(type: TraceLocationType): Promise<boolean>;
  /**
   * Creates a graphic from the trace result and adds it to the map. If a trace has both aggregated geometries and elements as results, aggregated geometries will be used to generate this area.
   *
   * @param trace - The aggregate of the trace configuration settings and the results for that trace.
   * @since 4.27
   */
  addResultAreaToMap(trace: TraceResultExtend): Promise<void>;
  /**
   * Create a graphic on the view's [MapView.graphics](https://developers.arcgis.com/javascript/latest/references/core/views/MapView/#graphics) for the aggregated results of all the features returned by the trace.
   *
   * @param trace - The aggregate of the trace configuration settings and the results for that trace.
   * @param color - The color for the graphic of the trace results in the view's [MapView.graphics](https://developers.arcgis.com/javascript/latest/references/core/views/MapView/#graphics).
   * @returns Resolves when the graphics are added to the view.
   */
  addResultGraphicToView(trace: TraceResultExtend, color: GraphicColor): Promise<void>;
  /**
   * Adds the selected terminal to a flag point.
   *
   * @param selectedTerminal - The terminal id of the selected terminal.
   * @param feature - The flag to assign the terminal.
   */
  addTerminal(selectedTerminal: string, feature: FlagProperty): void;
  /**
   * Get all parameters for the trace type selected to be run before executing the trace.
   *
   * @returns When resolved, response is `true` when the parameters from the trace type have loaded.
   */
  callTrace(): Promise<boolean>;
  /**
   * Change the graphic color for the aggregated results of a trace.
   *
   * @param color - The color for the graphic of the trace results in the view's [MapView.graphics](https://developers.arcgis.com/javascript/latest/references/core/views/MapView/#graphics).
   * @param trace - The aggregate of the trace configuration settings and the results for that trace.
   */
  changeResultGraphicColor(color: GraphicColor, trace: TraceResultExtend): void;
  /**
   * May be used to verify if all requirements are met to execute a trace (at least 1 starting point and at least 1 trace type selected).
   *
   * @returns Represents whether a trace is setup correctly.
   */
  checkCanTrace(): ValidSetup;
  /**
   * Indicates if any selection exists on the view.
   *
   * @returns Returns `true` if selection exists on the view.
   */
  checkSelectionExist(): boolean;
  /**
   * Removes a specific trace from the results. This will also clear any graphics or selection in the view for that trace.
   *
   * @param trace - The trace that will be cleared.
   */
  clearResult(trace: TraceItem): void;
  /**
   * Creates a buffer or convex hull graphic of the trace result.
   *
   * @param traceResults - The aggregate of the trace configuration settings and the results for that trace.
   * @returns Buffer or convex hull graphic of trace result.
   */
  createResultAreaGraphic(traceResults: TraceResultExtend): Promise<Graphic | null | undefined>;
  /**
   * Executes the trace and returns all trace results as graphics and/or feature selections and functions.
   *
   * @param traceItem - The trace item input for the trace.
   * @param url - The URL of the service being traced.
   * @param params - The trace input parameters.
   * @returns Represents the trace results and its properties.
   */
  executeTrace(traceItem: TraceItem, url: string, params: TraceParameters): Promise<TraceResultExtend>;
  /**
   * Gets the valid edge and junction layers within the view that are part of the Utility Network and can be used for placing flags in the view.
   *
   * @returns The edge or junction layer info.
   */
  getValidSources(): Array<NetworkSourceJSON>;
  /**
   * Reads the web map and loads the [UtilityNetwork](https://developers.arcgis.com/javascript/latest/references/core/networks/UtilityNetwork/) if it exists.
   *
   * @returns Resolves when the [UtilityNetwork](https://developers.arcgis.com/javascript/latest/references/core/networks/UtilityNetwork/) has been loaded.
   */
  loadUtilityNetwork(): Promise<UtilityNetwork | null | undefined>;
  /**
   * Enables or disables the filter barrier setting on barrier flags.
   *
   * @param status - Whether the filter barrier is enabled or disabled.
   * @param feature - The barrier flag for which the filter barrier is enabled or disabled.
   */
  manageFilterBarrier(status: boolean, feature: FlagProperty): void;
  /**
   * Is used to merge the feature selections in the layer views when multiple traces are run.
   *
   * @param status - If true, the trace selection results are part of the merged selection set.
   * @param trace - The trace for which the status is defined.
   */
  mergeSelection(status: boolean, trace: TraceItem): void;
  /**
   * Query the layers by ObjectID for more attributes not present on the trace result elements.
   *
   * @param dataItems - An array of [NetworkElements](https://developers.arcgis.com/javascript/latest/references/core/rest/networks/support/NetworkElement/).
   * @returns When resolved, an array of [FeatureSetInfo](https://developers.arcgis.com/javascript/latest/references/core/networks/support/utils/#FeatureSetInfo) is returned.
   */
  queryFeaturesById(dataItems: NetworkElement[]): Promise<FeatureSetInfo[] | null | undefined>;
  /**
   * Takes the result of a hit test to lookup the asset to create a flag for the trace.
   *
   * @param event - The create event.
   * @param flagType - The type of flag. It must be `"starting point"`, `"stopping point"`, or `"barrier"`.
   * @returns When resolved, returns `true` for a successful hitTest.
   */
  queryFlagByHitTest(event: CreateEvent, flagType: TraceLocationType): Promise<boolean>;
  /** Removes all the graphics from the result area graphic layer */
  removeAllResultAreaGraphics(): void;
  /**
   * Removes the selected flag from the view.
   *
   * @param flag - The [FlagProperty](https://developers.arcgis.com/javascript/latest/references/core/widgets/UtilityNetworkTrace/UtilityNetworkTraceViewModel/#FlagProperty) to identify the flag to be removed.
   */
  removeFlag(flag: FlagProperty): void;
  /**
   * Removes the result area graphic from the `Map`.
   *
   * @param trace - The aggregate of the trace configuration settings and the results for that trace.
   * @since 4.27
   */
  removeResultAreaFromMap(trace: TraceResultExtend): void;
  /**
   * Removes a specific trace result graphic from the view's [MapView.graphics](https://developers.arcgis.com/javascript/latest/references/core/views/MapView/#graphics).
   *
   * @param trace - The trace for which the graphic will be removed.
   */
  removeResultGraphicFromView(trace: TraceResultExtend): void;
  /** Removes the selection from the layer view. */
  removeSelection(): void;
  /**
   * Removes the selected terminal from the flag.
   *
   * @param selectedTerminal - The terminal id of the selected terminal.
   * @param feature - The flag to remove the terminal.
   */
  removeTerminal(selectedTerminal: string, feature: FlagProperty): void;
  /** Clears all inputs (flags, trace types) and all results (selections, graphics) in the view. */
  reset(): void;
  /**
   * Performs a selection on a layer view based on a list of ObjectIDs.
   *
   * @param resultSet - An array of [NetworkElements](https://developers.arcgis.com/javascript/latest/references/core/rest/networks/support/NetworkElement/).
   */
  selectFeaturesById(resultSet: NetworkElement[]): void;
  /**
   * Loops through the trace result elements to group them by network source id and selects them on the layer view.
   *
   * @param resultSet - An array of [NetworkElements](https://developers.arcgis.com/javascript/latest/references/core/rest/networks/support/NetworkElement/).
   */
  selectResults(resultSet: NetworkElement[]): void;
  /**
   * Set the trace type to be run from the available trace configurations in the [WebMap](https://developers.arcgis.com/javascript/latest/references/core/WebMap/).
   *
   * @param state - This is `true` if the trace is selected.
   * @param traceId - The globalid of the trace configuration.
   */
  selectTraces(state: boolean, traceId: string): void;
  /** Preset a trace type to be run from the available [trace configurations](https://developers.arcgis.com/javascript/latest/references/core/networks/UtilityNetwork/#sharedNamedTraceConfigurations) in the [WebMap](https://developers.arcgis.com/javascript/latest/references/core/WebMap/) when the widget loads. */
  selectTracesOnLoad(): void;
  /**
   * Zoom to a flag's feature or a result feature in the view.
   *
   * @param geometry - The geometry to zoom to.
   */
  zoomToAsset(geometry: GoToTarget2D | GoToTarget3D): void;
}