import type Analysis from "./Analysis.js";
import type LineOfSightAnalysisObserver from "./LineOfSightAnalysisObserver.js";
import type LineOfSightAnalysisTarget from "./LineOfSightAnalysisTarget.js";
import type Collection from "../core/Collection.js";
import type { LineOfSightAnalysisObserverProperties } from "./LineOfSightAnalysisObserver.js";
import type { LineOfSightAnalysisTargetProperties } from "./LineOfSightAnalysisTarget.js";
import type { ReadonlyArrayOrCollection } from "../core/Collection.js";
import type { AnalysisProperties } from "./Analysis.js";

export interface LineOfSightAnalysisProperties extends AnalysisProperties {
  /** Observer location. This is the point from which line of sight analysis is performed. */
  observer?: LineOfSightAnalysisObserverProperties | null;
  /** Target locations. A list of points to look at from the observer. */
  targets?: ReadonlyArrayOrCollection<LineOfSightAnalysisTargetProperties>;
}

/**
 * LineOfSightAnalysis computes the line of sight from a single observer position towards
 * a set of targets. The results are visualized in a 3D [SceneView](https://developers.arcgis.com/javascript/latest/references/core/views/SceneView/).
 *
 * To display the line of sight between two points, create a new instance of LineOfSightAnalysis,
 * add it to [SceneView.analyses](https://developers.arcgis.com/javascript/latest/references/core/views/SceneView/#analyses), and set the [observer](https://developers.arcgis.com/javascript/latest/references/core/analysis/LineOfSightAnalysis/#observer) and
 * [targets](https://developers.arcgis.com/javascript/latest/references/core/analysis/LineOfSightAnalysis/#targets) properties.
 *
 * If the [observer position](https://developers.arcgis.com/javascript/latest/references/core/analysis/LineOfSightAnalysisObserver/#position) or
 * [target position](https://developers.arcgis.com/javascript/latest/references/core/analysis/LineOfSightAnalysisTarget/#position) have [z-values](https://developers.arcgis.com/javascript/latest/references/core/geometry/Point/#hasZ)
 * then these will be treated as absolute values, otherwise the points will be aligned to the ground.
 *
 * Use the [LineOfSightAnalysisView3D](https://developers.arcgis.com/javascript/latest/references/core/views/3d/analysis/LineOfSightAnalysisView3D/) to retrieve
 * analysis results.
 *
 * ```js
 * // create line of sight analysis
 * const lineOfSightAnalysis = new LineOfSightAnalysis({
 *   observer: new LineOfSightAnalysisObserver({ position: new Point({ }) }),
 *   targets: [
 *     new LineOfSightAnalysisTarget({ position: new Point({ }) })
 *   ]
 * });
 *
 * // add to the view
 * view.analyses.add(lineOfSightAnalysis);
 *
 * // wait until the view finishes updating so the results are current
 * await reactiveUtils.whenOnce(() => !view.updating);
 *
 * // retrieve the results from the analysis view.
 * const analysisView = await view.whenAnalysisView(lineOfSightAnalysis);
 * const results = analysisView.results;
 * ```
 *
 * The line of sight analysis can also be added to a [LineOfSightLayer](https://developers.arcgis.com/javascript/latest/references/core/layers/LineOfSightLayer/) which can be persisted
 * in a web scene:
 *
 * ```js
 * // create line of sight layer containing the analysis
 * const lineOfSightLayer = new LineOfSightLayer({
 *   analysis: lineOfSightAnalysis
 * });
 *
 * // add to the map
 * view.map.add(lineOfSightLayer);
 * ```
 *
 * To place the observer and targets interactively, use the
 * [LineOfSightAnalysisView3D.place()](https://developers.arcgis.com/javascript/latest/references/core/views/3d/analysis/LineOfSightAnalysisView3D/#place) method.
 *
 * ```js
 * const abortController = new AbortController();
 *
 * try {
 *   await analysisView.place({ signal: abortController.signal });
 * } catch (error) {
 *   if (error.name === "AbortError") {
 *     console.log("Placement operation was cancelled.");
 *   }
 * }
 *
 * // cancel the placement operation at some later point
 * abortController.abort();
 * ```
 *
 * The analysis results are displayed as colored lines, where areas visible to the observer are
 * shown green and occluded parts are marked in red. Also, the color of the target points indicates their visibility.
 * When the line of sight cannot be calculated, it will be displayed with a gray color. This may happen if either
 * the target or the observer is not in the view.
 *
 * Use the [Line Of Sight component](https://developers.arcgis.com/javascript/latest/references/map-components/components/arcgis-line-of-sight/) to display a user interface
 * for the line of sight analysis.
 *
 * > [!WARNING]
 * >
 * > **Known Limitation**
 * >
 * > This analysis is only supported in a 3D [SceneView](https://developers.arcgis.com/javascript/latest/references/core/views/SceneView/).
 * > The results of the tool vary depending on the zoom level, as changes in zoom level affect the level of detail (LOD) of the scene geometry.
 *
 * @since 4.23
 * @see [LineOfSightAnalysisView3D](https://developers.arcgis.com/javascript/latest/references/core/views/3d/analysis/LineOfSightAnalysisView3D/)
 * @see [LineOfSightLayer](https://developers.arcgis.com/javascript/latest/references/core/layers/LineOfSightLayer/)
 * @see [LineOfSightLayerView](https://developers.arcgis.com/javascript/latest/references/core/views/layers/LineOfSightLayerView/)
 * @see [LineOfSightAnalysisTarget](https://developers.arcgis.com/javascript/latest/references/core/analysis/LineOfSightAnalysisTarget/)
 * @see [LineOfSightAnalysisObserver](https://developers.arcgis.com/javascript/latest/references/core/analysis/LineOfSightAnalysisObserver/)
 * @see [Line Of Sight component](https://developers.arcgis.com/javascript/latest/references/map-components/components/arcgis-line-of-sight/)
 * @see [Sample - Analysis objects](https://developers.arcgis.com/javascript/latest/sample-code/analysis-objects/)
 * @see [Sample - Line of sight component](https://developers.arcgis.com/javascript/latest/sample-code/line-of-sight/)
 */
export default class LineOfSightAnalysis extends Analysis {
  constructor(properties?: LineOfSightAnalysisProperties);
  /** Observer location. This is the point from which line of sight analysis is performed. */
  get observer(): LineOfSightAnalysisObserver | null | undefined;
  set observer(value: LineOfSightAnalysisObserverProperties | null | undefined);
  /** Target locations. A list of points to look at from the observer. */
  get targets(): Collection<LineOfSightAnalysisTarget>;
  set targets(value: ReadonlyArrayOrCollection<LineOfSightAnalysisTargetProperties>);
  /** The type of analysis. For line of sight analysis, this is always "line-of-sight". */
  get type(): "line-of-sight";
  /**
   * Indicates whether the analysis is ready to be computed and interacted with in the view.
   * It requires an [observer](https://developers.arcgis.com/javascript/latest/references/core/analysis/LineOfSightAnalysis/#observer) with a position.
   *
   * @since 4.33
   */
  get valid(): boolean;
  /**
   * Clears the analysis by resetting the [observer](https://developers.arcgis.com/javascript/latest/references/core/analysis/LineOfSightAnalysis/#observer) property and removing all
   * [targets](https://developers.arcgis.com/javascript/latest/references/core/analysis/LineOfSightAnalysis/#targets).
   *
   * @since 5.0
   */
  clear(): void;
}