/**
 * Various utilities for the Scene Viewer application.
 *
 * @experimental
 * @internal
 */
import type Graphic from "../../Graphic.js";
import type WebScene from "../../WebScene.js";
import type EsriError from "../../core/Error.js";
import type SpatialReference from "../../geometry/SpatialReference.js";
import type Layer from "../../layers/Layer.js";
import type BuildingComponentSublayer from "../../layers/buildingSublayers/BuildingComponentSublayer.js";
import type TileInfo from "../../layers/support/TileInfo.js";
import type SceneView from "../../views/SceneView.js";
import type BuildingComponentSublayerView from "../../views/layers/BuildingComponentSublayerView.js";
import type LayerView from "../../views/layers/LayerView.js";
import type LayerList from "../../widgets/LayerList.js";
import type Widget from "../../widgets/Widget.js";
import type EditorViewModel from "../../widgets/Editor/EditorViewModel.js";
import type { Unit } from "../../core/units.js";

/**
 * @experimental
 * @internal
 */
export interface DefaultsFromMapRequiredComponents {
  /** @experimental */
  extent: boolean;
  /** @experimental */
  heightModelInfo: boolean;
  /** @experimental */
  tileInfo: boolean;
}

/**
 * Settings to be used for the `defaultsFromMap` of a view.
 *
 * @experimental
 * @internal
 */
export interface DefaultsFromMapSettings {
  /**
   * The default spatial reference.
   *
   * @experimental
   */
  defaultSpatialReference?: SpatialReference;
  /**
   * Function which checks if a spatial reference is supported.
   *
   * @experimental
   */
  isSpatialReferenceSupported?: IsSpatialReferenceSupportedCallback;
  /**
   * Layers to prioritize.
   *
   * @experimental
   */
  priorityLayers?: Layer[];
  /**
   * The required components.
   *
   * @experimental
   */
  required?: DefaultsFromMapRequiredComponents;
}

/**
 * Callback function to check if a spatial reference is supported.
 *
 * @param spatialReference - The spatial reference to check.
 * @param layer - The layer to check.
 * @returns `true` if the spatial reference is supported.
 * @experimental
 * @internal
 */
export type IsSpatialReferenceSupportedCallback = (spatialReference: SpatialReference, layer?: Layer) => boolean;

/**
 * Allows setting overrides for the `defaultsFromMap` used by a view.
 *
 * @param view
 * @param settings
 * @experimental
 * @internal
 */
export function setDefaultsFromMapSettings(view: SceneView, settings: DefaultsFromMapSettings): void;

/**
 * Navigates back to the previous page of the `Editor` widget. If cancelling the active workflow
 * could cause lost data (e.g. some attributes were modified), the user is asked whether they wish
 * to discard their changes.
 *
 * @param viewModel - view model.
 * @experimental
 * @internal
 */
export function editorNavigateBack(viewModel: EditorViewModel): Promise<void>;

/**
 * Gets whether the editor still has any pending edits which should/could prevent the widget being
 * discarded/destroyed (e.g. when navigating to another pane in the SceneViewer).
 *
 * @param viewModel - view model.
 * @experimental
 * @internal
 */
export function editorHasPendingEdits(viewModel: EditorViewModel): boolean;

/**
 * Warn about problem when trying to display message about the save state.
 *
 * @param warningMessage - A warning message for the end user.
 * @param error - The returned error message.
 * @experimental
 * @internal
 */
export function saveStateWarning(warningMessage: string, error: any): void;

/**
 * @param url - URL to the hosted AGOL service.
 * @returns Indicates whether the service is an AGOL service.
 * @experimental
 * @internal
 */
export function isHostedAgolServiceUrl(url: string): boolean;

/**
 * Render svg vnode for elements provided in the descriptor
 *
 * @param swatch - the svg elements to renders
 * @param width - width
 * @param height - height
 * @param options - additional options
 * @returns if it is an hosted AGOL service.
 * @experimental
 * @internal
 */
export function renderSVG(swatch: any[][], width: number, height: number, options?: any): any;

/**
 * Checks for relative urls and returns whether or not this webscene allows the `saveAs()`
 * operation. Copying a WebScene is only allowed if there are no relative item URLs such that
 * things don't get weird once the "root WebScene" gets moved and/or deleted.
 *
 * @param webscene - The webscene to be checked.
 * @returns `true` if the webscene can be copied, `false` otherwise.
 * @experimental
 * @internal
 */
export function canSaveAs(webscene: WebScene): boolean;

/**
 * Checks whether the provided spatial reference is supported in the provided viewing mode.
 *
 * @param spatialReference - The spatial reference to check.
 * @param viewingMode - The viewing mode to check.
 * @returns `true` if the provided spatial reference is supported in the provided viewing mode, `false` otherwise.
 * @experimental
 * @internal
 */
export function isSpatialReferenceSupported(spatialReference: SpatialReference, viewingMode: "global" | "local"): boolean;

/**
 * Generates, if necessary, an equivalent TileInfo but with a different pixel size (256 or 512).
 *
 * @param tileInfo - input tileInfo to be compatible with
 * @param expectedTileSize - the expected tile size.
 * @returns the tileInfo with the correct tile size.
 * @experimental
 * @internal
 */
export function getCompatibleTileInfoForVTL(tileInfo: TileInfo, expectedTileSize: 256 | 512): TileInfo | null | undefined;

/**
 * Create a new TilingScheme based on the tileInfo
 *
 * @param tileInfo - tileInfo to create TilingScheme
 * @returns the tiling scheme
 * @experimental
 * @internal
 */
export function createTilingScheme(tileInfo: TileInfo): any;

/**
 * Check if a given TileInfo is supported.
 *
 * @param tileInfo - tileInfo to check
 * @returns `true` if the given `tileInfo` is supported.
 * @experimental
 * @internal
 */
export function isSupportedTileInfo(tileInfo: TileInfo): boolean;

/**
 * Initializes all the schema validators so that validation is performed when saving web scenes or
 * layers.
 *
 * @experimental
 * @internal
 */
export function initializeSchemaValidators(): void;

/**
 * Check if the error is a schema validation error.
 *
 * @param saveError - error thrown during webscene serialization.
 * @returns `true` if the error is a schema validation error.
 * @experimental
 * @internal
 */
export function isSchemaValidationError(saveError: EsriError): boolean;

/**
 * Returns the start position of the cross hair while dragging to zoom.
 *
 * @param view
 * @returns The start position of the drag while zooming.
 * @experimental
 * @internal
 */
export function zoomDragBeginPoint(view: SceneView): number[] | null | undefined;

/**
 * Helper function to close a catalog layer in the layer list.
 *
 * @param layerList
 * @experimental
 * @internal
 */
export function closeCatalogLayer(layerList: LayerList): void;

/**
 * Helper function to retrieve a popup feature from a LayerView or the underlying FeatureLayer.
 *
 * @param layerView
 * @param graphics
 * @returns The graphics populated with popup attributes.
 * @experimental
 * @internal
 */
export function fetchPopupFeaturesFromGraphics(layerView: LayerView | BuildingComponentSublayerView, graphics: Graphic[]): Promise<Graphic[]>;

/**
 * Helper function to convert a quantity of a source unit to a quantity of a destination unit.
 *
 * @param quantity
 * @param srcUnit
 * @param destUnit
 * @returns The converted quantity based on the destination unit.
 * @experimental
 * @internal
 */
export function convertToUnit(quantity: number, srcUnit: Unit, destUnit: Unit): number;

/**
 * Helper function to remove the html element (container) from a widget.
 *
 * @param widget
 * @experimental
 * @internal
 */
export function removeWidgetContainer(widget: Widget): void;

/**
 * Helper function to get the widgets rendered with JSX.
 *
 * @experimental
 * @internal
 */
export function getJsxWidgetMap(): Map<HTMLElement, Widget>;

/**
 * Helper function to get the symbol to access the projector on the JSX widget.
 *
 * @experimental
 * @internal
 */
export function getWidgetTestDataSymbol(): symbol;

/**
 * Helper function which checks the required WebGL capabilities
 * for the given view type and returns an error if requirements are not met.
 *
 * @param viewType
 * @returns An error if the client does not fulfill the WebGL requirements.
 * @experimental
 * @internal
 */
export function checkWebGLRequirements(viewType: "2d" | "3d"): EsriError | null | undefined;

/**
 * Helper function to retrieve the source layer of a graphic with source layer of type BuildingComponentSubLayer.
 *
 * @param graphic
 * @returns The source BuildingComponentSublayer of the graphic.
 * @experimental
 * @internal
 */
export function getSourceLayerFromBuildingComponentSublayerGraphic(graphic: Graphic): BuildingComponentSublayer | null | undefined;

/**
 * Helper function to set the source layer of a graphic using a layer of type BuildingComponentSubLayer
 *
 * @param graphic
 * @param sublayer
 * @experimental
 * @internal
 */
export function setSourceLayerOfBuildingComponentSublayerGraphic(graphic: Graphic, sublayer: BuildingComponentSublayer): void;