import type Graphic from "../Graphic.js";
import type Layer from "../layers/Layer.js";
import type FeatureLayer from "../layers/FeatureLayer.js";
import type SubtypeSublayer from "../layers/support/SubtypeSublayer.js";
import type CircuitManager from "./CircuitManager.js";
import type Network from "./Network.js";
import type UnitIdentifierManager from "./UnitIdentifierManager.js";
import type NamedTraceConfiguration from "./support/NamedTraceConfiguration.js";
import type NetworkSystemLayers from "./support/NetworkSystemLayers.js";
import type Terminal from "./support/Terminal.js";
import type TerminalConfiguration from "./support/TerminalConfiguration.js";
import type TraceJobInfo from "./support/TraceJobInfo.js";
import type Association from "../rest/networks/support/Association.js";
import type AssociationGeometriesResult from "../rest/networks/support/AssociationGeometriesResult.js";
import type NetworkElement from "../rest/networks/support/NetworkElement.js";
import type TraceResult from "../rest/networks/support/TraceResult.js";
import type { AbortOptions } from "../core/promiseUtils.js";
import type { RequestOptions } from "../request/types.js";
import type { ServiceEdits } from "../rest/featureService/types.js";
import type { QueryAssociationsParametersProperties } from "../rest/networks/support/QueryAssociationsParameters.js";
import type { SynthesizeAssociationGeometriesParametersProperties } from "../rest/networks/support/SynthesizeAssociationGeometriesParameters.js";
import type { TraceParametersProperties } from "../rest/networks/support/TraceParameters.js";
import type { NamedTraceConfigurationProperties } from "./support/NamedTraceConfiguration.js";
import type { NetworkProperties } from "./Network.js";

export interface UtilityNetworkProperties extends NetworkProperties {
  /**
   * This property returns the list of trace configurations shared on the webmap.
   * It is empty when no trace configurations are shared on the webmap.
   * This property can be used without fully loading the utility network, but only the `globalId` and the `title` will be available.
   */
  sharedNamedTraceConfigurations?: NamedTraceConfigurationProperties[];
}

export type SynthesizeAssociationGeometriesProperties = Pick<SynthesizeAssociationGeometriesParametersProperties, "returnAttachmentAssociations" | "returnConnectivityAssociations" | "returnContainmentAssociations" | "extent" | "maxGeometryCount" | "outSpatialReference">;

export type TraceProperties = Pick<TraceParametersProperties, "namedTraceConfigurationGlobalId" | "traceLocations" | "outSpatialReference" | "traceConfiguration" | "resultTypes" | "traceType">;

export type QueryAssociationsProperties = Pick<QueryAssociationsParametersProperties, "returnDeletes" | "elements" | "types">;

/**
 * This class contains metadata about the utility network dataset
 * retrieved from a [WebMap](https://developers.arcgis.com/javascript/latest/references/core/WebMap/). To access the full properties, users need
 * to call webmap's [WebMap.load()](https://developers.arcgis.com/javascript/latest/references/core/WebMap/#load) method. Certain properties are available without calling load
 * such as `id` and `title`. In 4.20, this object can only be retrieved from a webmap which has a utility network layer.
 *
 * @since 4.20
 * @see [NamedTraceConfiguration](https://developers.arcgis.com/javascript/latest/references/core/networks/support/NamedTraceConfiguration/)
 * @see [Terminal](https://developers.arcgis.com/javascript/latest/references/core/networks/support/Terminal/)
 * @see [TerminalConfiguration](https://developers.arcgis.com/javascript/latest/references/core/networks/support/TerminalConfiguration/)
 * @example
 * const [WebMap, MapView, esriConfig] = await $arcgis.import([
 *   "@arcgis/core/WebMap.js",
 *   "@arcgis/core/views/MapView.js",
 *   "@arcgis/core/config.js"
 * ]);
 * let utilityNetwork;
 *
 * // set the hostname to the portal instance
 * esriConfig.portalUrl = "https://myHostName.domain.com/arcgis";
 *
 * const webMap = new WebMap({
 *   portalItem: {
 *     id: "webmapID"
 *   }
 * });
 *
 * const mapView = new MapView({
 *   map: webMap
 * });
 *
 * webMap.when(async () => {
 *   // check if webMap contains utility networks
 *   if (webMap.utilityNetworks.length > 0) {
 *     // assign the utility network at index 0
 *     utilityNetwork = webMap.utilityNetworks.at(0);
 *
 *     // trigger the loading of the UtilityNetwork instance
 *     await utilityNetwork.load();
 *   }
 * });
 * @example
 * // Instantiating a UtilityNetwork instance using layerUrl
 * const utilityNetwork = new UtilityNetwork({layerUrl: "https://hostName.com/server/rest/services/Test/FeatureServer/17"});
 * await utilityNetwork.load();
 */
export default class UtilityNetwork extends Network {
  constructor(properties?: UtilityNetworkProperties);
  /**
   * The associations table is used to store associations between network features.
   * Associations are used to define relationships between network features, such as containment or connectivity.
   */
  get associationsTable(): FeatureLayer | null | undefined;
  /**
   * Returns all the [domain networks](https://pro.arcgis.com/en/pro-app/latest/help/data/utility-network/domain-network.htm) in the utility network. Domain networks contain the network features through which your delivered resource flows.
   *
   * @see [Domain networks](https://pro.arcgis.com/en/pro-app/latest/help/data/utility-network/domain-network.htm)
   */
  get domainNetworkNames(): string[];
  /**
   * Returns true if the utility network data element includes a telecom domain network.
   *
   * @beta
   * @since 4.34
   * @see [Telecom domain network](https://pro.arcgis.com/en/pro-app/latest/help/data/utility-network/telecom-domain-networks.htm)
   */
  get hasTelecomNetwork(): boolean;
  /**
   * Contains the url and IDs of the utility network rules, subnetworks, and dirty areas tables or layers.
   *
   * @example
   * // Print out the dirty areas layer url in the utility network
   * view.when(async () => {
   *   // Check if the webmap contains utility networks
   *   if(webmap?.utilityNetworks?.length > 0) {
   *     // Assigns the utility network at index 0
   *     utilityNetwork = webmap.utilityNetworks.at(0);
   *
   *     // Load the utility network
   *     await utilityNetwork.load();
   *
   *     // Print the dirty areas layer url and id
   *     console.log(`Dirty areas layer id: ${utilityNetwork.networkSystemLayers.dirtyAreasLayerId}`);
   *     console.log(`Dirty areas layer url: ${utilityNetwork.networkSystemLayers.dirtyAreasLayerUrl}`);
   *   }
   * });
   * @example
   * // Print out the dirty areas layer url in the utility network
   * view.when(async () => {
   *   // Check if the webmap contains utility networks
   *   if(webmap?.utilityNetworks?.length > 0) {
   *     // Assigns the utility network at index 0
   *     utilityNetwork = webmap.utilityNetworks.at(0);
   *
   *     // Load the utility network
   *     await utilityNetwork.load();
   *
   *     // Print the dirty areas layer url and id
   *     console.log(`Dirty areas layer id: ${utilityNetwork.networkSystemLayers.dirtyAreasLayerId}`);
   *     console.log(`Dirty areas layer url: ${utilityNetwork.networkSystemLayers.dirtyAreasLayerUrl}`);
   *   }
   * });
   */
  get networkSystemLayers(): NetworkSystemLayers;
  /**
   * The layer id of the service territory class used to define the extent of the utility network.
   * Value is `null` when a service territory layer is not published to the feature service.
   */
  get serviceTerritoryFeatureLayerId(): number | null;
  /**
   * This property returns the list of trace configurations shared on the webmap.
   * It is empty when no trace configurations are shared on the webmap.
   * This property can be used without fully loading the utility network, but only the `globalId` and the `title` will be available.
   */
  get sharedNamedTraceConfigurations(): NamedTraceConfiguration[];
  set sharedNamedTraceConfigurations(value: NamedTraceConfigurationProperties[]);
  /**
   * Returns all the terminal configurations on the utility network.
   * Terminal configurations defines how many terminals a device has and how those terminals are setup.
   * Must load the utility network to access this.
   *
   * @see [Terminal Configurations](https://pro.arcgis.com/en/pro-app/latest/tool-reference/utility-networks/add-terminal-configuration.htm)
   */
  get terminalConfigurations(): TerminalConfiguration[];
  /**
   * The type of the dataset. Returns `utility` if the object represents a utility network.
   *
   * @default "utility"
   */
  get type(): "utility";
  /**
   * Returns `true` if the given [Association](https://developers.arcgis.com/javascript/latest/references/core/rest/networks/support/Association/) is valid.
   *
   * @param association - Association that needs to be validated.
   * @returns Returns true if given [Association](https://developers.arcgis.com/javascript/latest/references/core/rest/networks/support/Association/) is valid.
   * @since 4.29
   * @example
   * const association = new Association({
   *   globalId: "{88355CB3-B011-4715-BB90-047B8C7ABF48}",
   *   fromNetworkElement: new NetworkElement({
   *     globalId: "{09B7A0F9-811D-4CCF-95A9-D1995D44C631}",
   *     networkSourceId: 8,
   *     terminalId: 1,
   *     assetGroupCode: 1,
   *     assetTypeCode: 1,
   *    }),
   *   toNetworkElement: new NetworkElement({
   *     globalId: "{86DD4700-4D1B-4872-93CD-68783F7996B6}",
   *     networkSourceId: 10,
   *     terminalId: 1,
   *     assetGroupCode: 2,
   *     assetTypeCode: 2,
   *     }),
   *   associationType: "attachment",
   * });
   *
   * const isValidAssociation = await utilityNetwork.canAddAssociation(association);
   */
  canAddAssociation(association: Association): Promise<boolean>;
  /**
   * Returns [ServiceEdits](https://developers.arcgis.com/javascript/latest/references/core/rest/featureService/types/#ServiceEdits) which are used to add an [Association](https://developers.arcgis.com/javascript/latest/references/core/rest/networks/support/Association/) via the `applyEdits` method on the [FeatureService](https://developers.arcgis.com/javascript/latest/references/core/rest/featureService/FeatureService/) class.
   *
   * Note: it is advisable to load the associations layer before calling this method, which can be done by calling the [loadAssociationsTable()](https://developers.arcgis.com/javascript/latest/references/core/networks/UtilityNetwork/#loadAssociationsTable) method. Loading the associations table ensures that the attributes of the resulting associations use the correctly-cased field names. If the associations table is not loaded, the field names will be in lowercase.
   * Note: Use -1 if terminalId is null.
   *
   * @param associations - `Association` used to generate the [ServiceEdits](https://developers.arcgis.com/javascript/latest/references/core/rest/featureService/types/#ServiceEdits) object.
   * @returns Returns `ServiceEdits` which are used to add an [Association](https://developers.arcgis.com/javascript/latest/references/core/rest/networks/support/Association/) via the `applyEdits` method on the [FeatureService](https://developers.arcgis.com/javascript/latest/references/core/rest/featureService/FeatureService/) class.
   * @since 4.29
   * @example
   * const association = new Association({
   *   globalId: "{88355CB3-B011-4715-BB90-047B8C7ABF48}",
   *   fromNetworkElement: new NetworkElement({
   *     globalId: "{09B7A0F9-811D-4CCF-95A9-D1995D44C631}",
   *     networkSourceId: 8,
   *     terminalId: 1,
   *     assetGroupCode: 1,
   *     assetTypeCode: 1,
   *    }),
   *   toNetworkElement: new NetworkElement({
   *     globalId: "{86DD4700-4D1B-4872-93CD-68783F7996B6}",
   *     networkSourceId: 10,
   *     terminalId: 1,
   *     assetGroupCode: 2,
   *     assetTypeCode: 2,
   *     }),
   *   associationType: "attachment",
   * });
   *
   * const isValidAssociation = await utilityNetwork.canAddAssociation(association);
   * const generatedAssociations = utilityNetwork.generateAddAssociation([association]);
   *
   * const featureService = new FeatureService({ url: "https://hostName.com/server/rest/services/Test/FeatureServer" });
   * featureService.applyEdits([generatedAssociations],
   *  {
   *    gdbVersion: "unadmin.testVersion",
   *    globalIdUsed: false,
   *    honorSequenceOfEdits: false
   *    usePreviousEditMoment: false,
   *    returnServiceEditsInSourceSR: true,
   *  })
   */
  generateAddAssociations(associations: Association[]): ServiceEdits;
  /**
   * Returns [ServiceEdits](https://developers.arcgis.com/javascript/latest/references/core/rest/featureService/types/#ServiceEdits) to combine [network elements](https://developers.arcgis.com/javascript/latest/references/core/rest/networks/support/NetworkElement/)
   * in a telecom domain network via the `applyEdits` method on the [FeatureService](https://developers.arcgis.com/javascript/latest/references/core/rest/featureService/FeatureService/) class.
   *
   * The objects being combined must have consecutive unit IDs, exist in the same table and unit container,
   * and have the same attribute values.
   *
   * @param networkElements - The network elements to combine in a telecom domain network.
   * @returns `ServiceEdits` for combining network elements in a telecom domain network.
   * @beta
   * @since 4.34
   * @example
   * const networkElementA = new NetworkElement({
   *   globalId: "{6CE34136-EC3A-40D7-80BF-E1D9BE33812A}",
   *   networkSourceId: 20,
   * });
   *
   * const networkElementB = new NetworkElement({
   *   globalId: "{74100804-E229-49b8-8CDC-9B5D3EF03EDA}",
   *   networkSourceId: 20,
   * });
   *
   * const networkElementC = new NetworkElement({
   *   globalId: "{39B856DC-AFE4-4c02-B433-A9361ACD91CF}",
   *   networkSourceId: 20,
   * });
   *
   * const serviceEdits = utilityNetwork.generateCombineNetworkElements([
   *   networkElementA,
   *   networkElementB,
   *   networkElementC,
   * ]);
   *
   * await featureService.applyEdits([serviceEdits]);
   */
  generateCombineNetworkElements(networkElements: NetworkElement[]): ServiceEdits;
  /**
   * Returns [ServiceEdits](https://developers.arcgis.com/javascript/latest/references/core/rest/featureService/types/#ServiceEdits) which are used to delete an [Association](https://developers.arcgis.com/javascript/latest/references/core/rest/networks/support/Association/) via the `applyEdits` method on the [FeatureService](https://developers.arcgis.com/javascript/latest/references/core/rest/featureService/FeatureService/) class.
   *
   * @param associations - `Association` used to generate the [ServiceEdits](https://developers.arcgis.com/javascript/latest/references/core/rest/featureService/types/#ServiceEdits) object.
   * @returns Returns `ServiceEdits` which are used to delete an [Association](https://developers.arcgis.com/javascript/latest/references/core/rest/networks/support/Association/) via the `applyEdits` method on the [FeatureService](https://developers.arcgis.com/javascript/latest/references/core/rest/featureService/FeatureService/) class.
   * @since 4.29
   * @example
   * const association = new Association({
   *  globalId: "{323FF251-A5FC-4665-97A3-D78615C3DD21}",
   * });
   * const generatedDeleteAssociations = utilityNetwork.generateDeleteAssociations([association]);
   *
   * const featureService = new FeatureService({ url: "https://hostName.com/server/rest/services/Test/FeatureServer" });
   * featureService.applyEdits([generatedDeleteAssociations],
   *  {
   *    gdbVersion: "unadmin.testVersion",
   *    globalIdUsed: true, //globalIdUsed must be true when deleting associations with this workflow
   *    honorSequenceOfEdits: false
   *    usePreviousEditMoment: false,
   *    returnServiceEditsInSourceSR: true,
   *  })
   */
  generateDeleteAssociations(associations: Association[]): ServiceEdits;
  /**
   * Returns [ServiceEdits](https://developers.arcgis.com/javascript/latest/references/core/rest/featureService/types/#ServiceEdits) to divide a grouped [network element](https://developers.arcgis.com/javascript/latest/references/core/rest/networks/support/NetworkElement/)
   * in a telecom domain network into two or more grouped elements via the `applyEdits` method on the [FeatureService](https://developers.arcgis.com/javascript/latest/references/core/rest/featureService/FeatureService/) class.
   *
   * @param networkElement - The grouped network element in a telecom
   *   domain network to divide into two or more grouped elements.
   * @param numUnits - Describes how the unit identifiers of the grouped object should be divided.
   *   Each number in this array describes the number of units to assign an object resulting from the division.
   *   E.g., to divide one object with 6 units into an object with 5 units and another object with 1 unit, specify [5, 1].
   * @returns `ServiceEdits` for dividing a network element in a telecom domain network.
   * @beta
   * @since 4.34
   * @example
   * const networkElement = new NetworkElement({
   *   globalId: "{6CE34136-EC3A-40D7-80BF-E1D9BE33812A}",
   *   networkSourceId: 20,
   * });
   *
   * const serviceEdits = utilityNetwork.generateDivideNetworkElements(networkElement, [2, 3, 4]);
   *
   * await featureService.applyEdits([serviceEdits]);
   */
  generateDivideNetworkElements(networkElement: NetworkElement, numUnits: number[]): ServiceEdits;
  /**
   * Returns a [CircuitManager](https://developers.arcgis.com/javascript/latest/references/core/networks/CircuitManager/) for the utility network's telecom domain network, if one exists.
   *
   * @param telecomDomainNetworkName - The name of the telecom domain network to return a `CircuitManager` for.
   * @returns Resolves to a [CircuitManager](https://developers.arcgis.com/javascript/latest/references/core/networks/CircuitManager/)
   *   for the utility network's telecom domain network, or null if no such domain network exists.
   * @beta
   * @since 4.34
   */
  getCircuitManager(telecomDomainNetworkName: string): Promise<CircuitManager | null>;
  /**
   * Given a terminalId, returns the corresponding Terminal instance.
   *
   * @param terminalId - The terminalId used to retrieve the corresponding Terminal.
   * @returns An instance of [Terminal](https://developers.arcgis.com/javascript/latest/references/core/networks/support/Terminal/) that matches the specified `terminalId`, or `null` if no match is found.
   * @since 4.34
   */
  getTerminalById(terminalId?: number): Terminal | null | undefined;
  /**
   * All devices features have terminal configurations (default single terminal).
   * Users can use this method to retrieve the assigned terminal configuration of a given feature.
   * This method takes a graphic/feature, uses the `ASSETGROUP` and `ASSETTYPE` fields along side the
   * network source to find out the assigned terminal configuration. If either `ASSETGROUP`, `ASSETTYPE` or `layer` are not populated a `null` is returned.
   * Returns `null` if terminal configuration object couldn't be found.
   *
   * @param feature - The graphic feature to get the terminal configuration from. Must belong to a device layer, and have `ASSETGROUP` and `ASSETTYPE` fields populated.
   * @returns The terminal configuration object. Most devices have a single terminal configuration unless configured otherwise.
   */
  getTerminalConfiguration(feature: Graphic): TerminalConfiguration | null | undefined;
  /**
   * Takes the name of a domain network and returns an array with the names of its tiers. A [domain network](https://pro.arcgis.com/en/pro-app/latest/help/data/utility-network/domain-network.htm) can have one or several tiers. A tier is a subgrouping of a domain network that represents the logical hierarchy of subnetworks.
   *
   * @param domainNetworkName - The name of the domain network.
   * @returns Returns an array of tier names.
   * @see [Tiers - ArcGIS Pro](https://pro.arcgis.com/en/pro-app/latest/help/data/utility-network/tiers.htm)
   * @see [Domain networks - ArcGIS Pro](https://pro.arcgis.com/en/pro-app/latest/help/data/utility-network/domain-network.htm)
   */
  getTierNames(domainNetworkName: string): string[];
  /**
   * Returns a [UnitIdentifierManager](https://developers.arcgis.com/javascript/latest/references/core/networks/UnitIdentifierManager/) for the utility network's telecom domain networks, if any exist.
   *
   * @returns Resolves to a [UnitIdentifierManager](https://developers.arcgis.com/javascript/latest/references/core/networks/UnitIdentifierManager/)
   *   for the utility network's telecom domain networks, or null if no such domain network exists.
   * @beta
   * @since 4.34
   */
  getUnitIdentifierManager(): Promise<UnitIdentifierManager | null>;
  /**
   * Returns a boolean indicating if the layer is a utility layer belonging to the network.
   *
   * @param layer - The layer to check if it is a utility layer.
   * @returns value indicating membership of the layer in the utility network.
   * @since 4.32
   */
  isUtilityLayer(layer: Layer | SubtypeSublayer): boolean;
  /**
   * Triggers the loading of the UtilityNetwork instance.
   *
   * Fully loads the utility network definition and all the shared named trace configurations.
   *
   * @param options - Additional options.
   * @returns Resolves when the UtilityNetwork is [loaded](https://developers.arcgis.com/javascript/latest/references/core/networks/UtilityNetwork/#loaded).
   */
  load(options?: AbortOptions | null | undefined): Promise<this>;
  /**
   * Loads the Utility Network's associations table.
   *
   * @returns Resolves to a loaded instance of [FeatureLayer](https://developers.arcgis.com/javascript/latest/references/core/layers/FeatureLayer/) representing the associations table.
   * @since 4.32
   */
  loadAssociationsTable(): Promise<FeatureLayer>;
  /**
   * Loads the Utility Network's subnetworks table.
   *
   * @returns Resolves to a loaded instance of [FeatureLayer](https://developers.arcgis.com/javascript/latest/references/core/layers/FeatureLayer/) representing the subnetworks table.
   * @since 4.34
   */
  loadSubnetworksTable(): Promise<FeatureLayer>;
  /**
   * Returns all associations filtered by the [QueryAssociationsParameters](https://developers.arcgis.com/javascript/latest/references/core/rest/networks/support/QueryAssociationsParameters/) in a utility network.
   * The `gdbVersion` and `moment` properties of the `props` parameter will be hydrated from this [UtilityNetwork](https://developers.arcgis.com/javascript/latest/references/core/networks/UtilityNetwork/).
   *
   * @param props - Props consists of returnDeletes, elements, and types.
   * @param options - An object with the following properties.
   * @returns When resolved, the list of returned Associations from the query.
   * @since 4.28
   */
  queryAssociations(props: QueryAssociationsProperties, options?: RequestOptions): Promise<Association[]>;
  /**
   * The submitTraceJob method takes a set of parameters, executes the asynchronous trace on the backend, and returns trace results.
   * The `gdbVersion` and `moment` properties of the `props` parameter will be hydrated from this [UtilityNetwork](https://developers.arcgis.com/javascript/latest/references/core/networks/UtilityNetwork/).
   *
   * > [!WARNING]
   * >
   * > The `path` and `circuit` trace types are reserved for future use.
   *
   * @param props - Props consists of namedTraceConfigurationGlobalId, traceLocations, outSpatialReference, traceConfiguration, resultTypes, and traceType.
   * @returns Returns a Promise of TraceJobInfo.
   * @since 4.27
   */
  submitTraceJob(props: TraceProperties): Promise<TraceJobInfo>;
  /**
   * Given an extent, returns all associations within this extent and their synthesized geometries.
   * The `gdbVersion` and `moment` properties of the `props` parameter will be hydrated from this [UtilityNetwork](https://developers.arcgis.com/javascript/latest/references/core/networks/UtilityNetwork/).
   *
   * @param props - Props consists of extent, returnAttachmentAssociations, returnConnectivityAssociations, returnContainmentAssociations, maxGeometryCount, and outSpatialReference.
   * @returns When resolved, returns the association geometries result.
   * @since 4.28
   */
  synthesizeAssociationGeometries(props: SynthesizeAssociationGeometriesProperties): Promise<AssociationGeometriesResult>;
  /**
   * The trace method takes a set of parameters, executes the trace on the backend, and returns trace results.
   * The `gdbVersion` and `moment` properties of the `props` parameter will be hydrated from this [UtilityNetwork](https://developers.arcgis.com/javascript/latest/references/core/networks/UtilityNetwork/).
   *
   * > [!WARNING]
   * >
   * > The `path` and `circuit` trace types are reserved for future use.
   *
   * @param props - Props consists of namedTraceConfigurationGlobalId, traceLocations, outSpatialReference, traceConfiguration, resultTypes, and traceType.
   * @returns Returns a Promise of TraceResult.
   * @since 4.27
   */
  trace(props: TraceProperties): Promise<TraceResult>;
}