/**
 * Analysis utility functions for Web Components.
 *
 * @internal
 */
import type ElevationProfileAnalysisView2D from "../../views/2d/analysis/ElevationProfileAnalysisView2D.js";
import type AreaMeasurementAnalysisView3D from "../../views/3d/analysis/AreaMeasurementAnalysisView3D.js";
import type ElevationProfileAnalysisView3D from "../../views/3d/analysis/ElevationProfileAnalysisView3D.js";
import type { ResourceHandle } from "../../core/Handles.js";
import type { AbortOptions } from "../../core/promiseUtils.js";
import type { Length } from "../../core/quantity.js";
import type { MapViewOrSceneView } from "../../views/MapViewOrSceneView.js";
import type { AnalysisViewUnion } from "../../views/analysis/types.js";

/**
 * Forces the analysis view to be interactive until the returned handle is removed.
 *
 * @param analysisView - The analysis view whose `interactive` property is to be forced to `true`.
 * @returns A handle which, when removed, will restore the analysis view to its
 * original interactive state.
 * @experimental
 * @internal
 */
export function forceInteractive(analysisView: AnalysisViewUnion): ResourceHandle;

/**
 * Gets whether the specified length is above the geodesic distance threshold.
 *
 * @param length - The length to check.
 * @returns `true` if the specified length is geodesic, `false` otherwise.
 * @experimental
 * @internal
 */
export function isAboveGeodesicDistanceThreshold(length: Length): boolean;

/**
 * Gets whether the specified analysis view contains a valid result. The result is valid if there are no intersecting
 * segments on the geometry.
 *
 * @param analysisView - The analysis view to check.
 * @returns `true` if the analysis view contains a valid result, `false` otherwise.
 * @experimental
 * @internal
 */
export function hasValidAreaResult(analysisView: AreaMeasurementAnalysisView3D): boolean;

/**
 * Sets the elevation profile to a test configuration which removes timeouts, throtting, etc to make tests faster.
 *
 * @returns A watch handle.
 * @experimental
 * @internal
 */
export function setElevationProfileTestConfig(): ResourceHandle;

/**
 * An elevation profile chart.
 *
 * @experimental
 * @internal
 */
export interface InternalElevationProfileChart {
  /**
   * The ElevationProfileAnalysisView2D or ElevationProfileAnalysisView3D associated with the chart.
   *
   * @experimental
   */
  analysisView?: ElevationProfileAnalysisView2D | ElevationProfileAnalysisView3D | null;
  /**
   * Indicates whether the chart should be shown.
   *
   * @experimental
   */
  chartVisible: boolean;
  /**
   * Destroys the chart and releases resources.
   *
   * @experimental
   */
  destroy: () => void;
  /**
   * The messages used in the chart.
   *
   * @experimental
   */
  messages?: object | null;
  /**
   * Indicates whether the loading spinner should be shown.
   *
   * @experimental
   */
  spinnerVisible: boolean;
  /**
   * Testing utilities (only available when the `esri-tests` build flag is set to `true`).
   *
   * @experimental
   */
  test?: InternalElevationProfileChartTest;
  /**
   * Indicates whether uniform scaling is enabled for the chart axes.
   *
   * @experimental
   */
  uniformScaling: boolean;
  /**
   * The MapView or SceneView associated with the chart.
   *
   * @experimental
   */
  view?: MapViewOrSceneView | null;
  /**
   * Zooms out the chart to show the full range of data.
   *
   * @experimental
   */
  zoomOut: () => void;
}

/**
 * @experimental
 * @internal
 */
export interface InternalElevationProfileChartTest {
  /**
   * Shows the chart tooltip at the specified coordinates.
   *
   * @experimental
   */
  forceShowTooltipAt: (x: number, y: number) => Promise<void>;
  /**
   * Returns a promise that resolves when the chart is fully ready.
   *
   * @experimental
   */
  whenReady: () => Promise<void>;
}

/**
 * Factory method for lazy-loading and creating an elevation profile chart until we're able to fully use amCharts in
 * map-components along with the other things like unit and localization utilities.
 *
 * @param parameters
 * @returns The created chart instance.
 * @experimental
 * @internal
 */
export function createChart(parameters: InternalCreateChartParameters): Promise<InternalElevationProfileChart>;

/**
 * @experimental
 * @internal
 */
export interface InternalCreateChartParameters extends AbortOptions {
  /**
   * The analysis view to associate with the chart.
   *
   * @experimental
   */
  analysisView?: ElevationProfileAnalysisView2D | ElevationProfileAnalysisView3D | null;
  /**
   * The container element in which to render the chart.
   *
   * @experimental
   */
  container: HTMLElement;
  /**
   * Messages to display in the chart.
   *
   * @experimental
   */
  messages?: object | null;
  /**
   * Called when the cursor position changes on the chart.
   *
   * @experimental
   */
  onCursorPositionChange?: null | ((x: number | null | undefined, y: number | null | undefined) => void);
  /**
   * Called when the chart's range changes.
   *
   * @experimental
   */
  onRangeChange?: null | ((zoomFactorX: number, zoomFactorY: number) => void);
  /**
   * Whether to use uniform scaling for the chart axes.
   *
   * @experimental
   */
  uniformScaling?: boolean | null;
  /**
   * The MapView or SceneView instance associated with the chart.
   *
   * @experimental
   */
  view?: MapViewOrSceneView | null;
}