import type Graphic from "../Graphic.js";
import type Popup from "../widgets/Popup.js";
import type { AbortOptions } from "../core/promiseUtils.js";
import type { ScreenPoint, ScreenRect } from "../core/types.js";
import type { PointerType } from "./input/types.js";
import type { PopupProperties } from "../widgets/Popup.js";
import type { PopupOpenOptions } from "../widgets/Popup/types.js";

export interface PopupViewProperties extends Partial<Pick<PopupView, "popupEnabled">> {
  /**
   * A [Popup](https://developers.arcgis.com/javascript/latest/references/core/widgets/Popup/) object that displays general content or attributes from
   * [layers](https://developers.arcgis.com/javascript/latest/references/core/Map/#layers) in the [map](https://developers.arcgis.com/javascript/latest/references/core/views/View/#map).
   *
   * By default, the `popup` property is an empty object that allows you to set the popup options.
   * A [Popup](https://developers.arcgis.com/javascript/latest/references/core/widgets/Popup/) instance is automatically created and assigned to the view's [popup](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#popup)
   * when the user clicks on the view and [popupEnabled](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#popupEnabled) is `true`, when the [openPopup](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#openPopup) method is called,
   * or when some widgets need the popup, such as [Search](https://developers.arcgis.com/javascript/latest/references/core/widgets/Search/). If [popup](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#popup) is `null`, the popup instance will not be created.
   *
   * @see [popupEnabled](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#popupEnabled)
   * @see [openPopup()](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#openPopup)
   * @see [Loading the Popup](https://developers.arcgis.com/javascript/latest/references/core/widgets/Popup/#loading-the-popup)
   * @example
   * // Set the view's popup to a new Popup instance.
   * // The popup will show anytime a popup is called such as when selecting features or displaying a Search result.
   * view.popup = new Popup();
   * @example
   * // Set the popup to a PopupOptions object with popup properties set such as the dock options.
   * // The popup will show anytime a popup is called.
   * view.popup = {
   *  dockEnabled: true,
   *  dockOptions: {
   *    position: "top-left",
   *    breakpoint: false
   *  }
   * };
   * @example
   * // Set the popup to null. This disables the popup so it will never show up.
   * view.popup = null;
   */
  popup?: Popup | PopupProperties | null;
}

/**
 * Mixin for [View](https://developers.arcgis.com/javascript/latest/references/core/views/View/)s that provides popup functionality.
 *
 * @since 4.27
 */
export abstract class PopupView {
  constructor(...args: any[]);
  /**
   * A [Popup](https://developers.arcgis.com/javascript/latest/references/core/widgets/Popup/) object that displays general content or attributes from
   * [layers](https://developers.arcgis.com/javascript/latest/references/core/Map/#layers) in the [map](https://developers.arcgis.com/javascript/latest/references/core/views/View/#map).
   *
   * By default, the `popup` property is an empty object that allows you to set the popup options.
   * A [Popup](https://developers.arcgis.com/javascript/latest/references/core/widgets/Popup/) instance is automatically created and assigned to the view's [popup](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#popup)
   * when the user clicks on the view and [popupEnabled](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#popupEnabled) is `true`, when the [openPopup](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#openPopup) method is called,
   * or when some widgets need the popup, such as [Search](https://developers.arcgis.com/javascript/latest/references/core/widgets/Search/). If [popup](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#popup) is `null`, the popup instance will not be created.
   *
   * @see [popupEnabled](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#popupEnabled)
   * @see [openPopup()](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#openPopup)
   * @see [Loading the Popup](https://developers.arcgis.com/javascript/latest/references/core/widgets/Popup/#loading-the-popup)
   * @example
   * // Set the view's popup to a new Popup instance.
   * // The popup will show anytime a popup is called such as when selecting features or displaying a Search result.
   * view.popup = new Popup();
   * @example
   * // Set the popup to a PopupOptions object with popup properties set such as the dock options.
   * // The popup will show anytime a popup is called.
   * view.popup = {
   *  dockEnabled: true,
   *  dockOptions: {
   *    position: "top-left",
   *    breakpoint: false
   *  }
   * };
   * @example
   * // Set the popup to null. This disables the popup so it will never show up.
   * view.popup = null;
   */
  get popup(): Popup | null | undefined;
  set popup(value: Popup | PopupProperties | null | undefined);
  /**
   * Controls whether the popup opens when users click on the view.
   *
   * When `true`, a [Popup](https://developers.arcgis.com/javascript/latest/references/core/widgets/Popup/) instance is created
   * and assigned to [popup](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#popup) the first time the user clicks on the view,
   * unless [popup](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#popup) is `null`. The [popup](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#popup) then processes the click event.
   *
   * When `false`, the click event is ignored and [popup](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#popup) is not created for features but will open for other
   * scenarios that use a popup, such as displaying Search results.
   *
   * @default true
   * @since 4.27
   * @see [popup](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#popup)
   * @see [openPopup()](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#openPopup)
   * @example
   * // Disable the popup from automatically appearing and
   * // open the popup manually using a click event.
   * view.popupEnabled = false;
   * view.on("click", (event)=> {
   *   view.openPopup({
   *     // Set properties for the manually opened popup
   *     ...
   *   });
   * });
   */
  accessor popupEnabled: boolean;
  /**
   * Closes the popup.
   *
   * @since 4.27
   * @see [popup](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#popup)
   * @see [openPopup()](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#openPopup)
   * @example
   * // Closes the popup if it's open
   * if(view.popup.visible){
   *  view.closePopup();
   * }
   */
  closePopup(): void;
  /**
   * Use this method to query for features at a given screen location.
   * These features come from origins (layers and sublayers) configured with a [PopupTemplate](https://developers.arcgis.com/javascript/latest/references/core/PopupTemplate/)
   * and have its [FeatureLayer.popupEnabled](https://developers.arcgis.com/javascript/latest/references/core/layers/FeatureLayer/#popupEnabled) set.
   *
   * One example could be a custom side panel that displays feature-specific information based on
   * an end user's click location. This method allows a developer to
   * control how the input location is handled, and then subsequently, what to do with the results.
   *
   * > [!WARNING]
   * > Using [ScreenRect](https://developers.arcgis.com/javascript/latest/references/core/core/types/#ScreenRect) as the hit target is considered **[beta](https://developers.arcgis.com/javascript/latest/faq/#what-does-the-beta-tag-mean)** functionality.
   *
   * @param hitTarget
   * @param options
   * @returns An async generator of features ready to be displayed by the popup,
   *   with the attributes and geometry required by their popup template.
   *   Generator yields features as soon as they are available in the top to bottom order.
   * @since 5.1
   * @example
   * // Consume features from the generator as soon as they are available
   * view.on("click", async (event) => {
   *   const generator = view.fetchPopupFeatures(event.screenPoint, {
   *     pointerType: event.pointerType
   *   });
   *
   *   for await (const feature of generator) {
   *     console.log(feature);
   *   }
   * });
   * @example
   * // Wait for all the features to be available
   * view.on("click", async (event) => {
   *   const generator = view.fetchPopupFeatures(event.screenPoint, {
   *     pointerType: event.pointerType
   *   });
   *
   *   const features = await Array.fromAsync(generator);
   *
   *   console.log(`${features.length} available for popup`);
   * });
   * @example
   * // Get the top most feature
   * view.on("click", async (event) => {
   *   const controller = new AbortController();
   *   const generator = view.fetchPopupFeatures(event.screenPoint, {
   *     pointerType: event.pointerType,
   *     signal: controller.signal
   *   });
   *
   *   const result = await generator.next();
   *   const feature = result.done ? null : result.value;
   *
   *   // abort the pending iterations
   *   controller.abort();
   *
   *   console.log(`top most feature`, feature);
   * });
   */
  fetchPopupFeatures(hitTarget: ScreenPoint | ScreenRect, options?: FetchPopupFeaturesOptions): AsyncGenerator<Graphic>;
  /**
   * Opens the popup at the given location with content defined either explicitly with `content`
   * or driven from the [PopupTemplate](https://developers.arcgis.com/javascript/latest/references/core/PopupTemplate/) of input features. This method sets
   * the popup's [visible](https://developers.arcgis.com/javascript/latest/references/core/widgets/Popup/#visible) property to `true`. Users can alternatively open the popup
   * by directly setting the [visible](https://developers.arcgis.com/javascript/latest/references/core/widgets/Popup/#visible) property to `true`.
   *
   * A [Popup](https://developers.arcgis.com/javascript/latest/references/core/widgets/Popup/) instance is created
   * and assigned to [popup](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#popup) the first time `openPopup()` is called,
   * unless [popup](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#popup) is `null`.
   * The [popup](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#popup) then processes the click event.
   *
   * When calling this method, to prevent the popup from opening when clicking on the view, set [popupEnabled](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#popupEnabled) to `false` to stop event propagation on the view.
   *
   * > [!WARNING]
   * >
   * > The popup will only display if
   * > the view's size constraints in [dockOptions](https://developers.arcgis.com/javascript/latest/references/core/widgets/Popup/#dockOptions) are met or the [location](https://developers.arcgis.com/javascript/latest/references/core/widgets/Popup/#location)
   * > property is set to a geometry.
   *
   * @param options - Defines the location and content of the popup when opened.
   * @returns Resolves when the popup is opened. Calling `openPopup()` or `closePopup()` again rejects the Promise.
   * @since 4.27
   * @see [popup](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#popup)
   * @see [closePopup()](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#closePopup)
   * @see [Popup.open()](https://developers.arcgis.com/javascript/latest/references/core/widgets/Popup/#open)
   * @see [Intro to popups](https://developers.arcgis.com/javascript/latest/sample-code/intro-popup/)
   * @see [Sample - Query with `rest/query`](https://developers.arcgis.com/javascript/latest/sample-code/query/)
   * @see [Sample - Popup with DOM node](https://developers.arcgis.com/javascript/latest/sample-code/popup-domnode/)
   * @example
   * // Opens a popup manually depending on where the user clicks with specified title and content.
   * view.on("click", (event)=>{
   *   view.openPopup({
   *    location: event.mapPoint,
   *    title: "You clicked here",
   *    content: "This is a point of interest"
   *   });
   * });
   * @example
   * // Opens popup at the location of the click event and displays
   * // content for the selected features if a popupTemplate is defined.
   *  view.on("click", (event)=>{
   *    view.openPopup({
   *      location: event.mapPoint,
   *      fetchFeatures: true
   *    });
   *  });
   * @example
   * // Opens popup with the properties specified at the location of the click event
   * // and updates the popup location based on the selected feature's geometry.
   * view.openPopup({
   *   title: "You clicked here",
   *   content: "This is a point of interest",
   *   location: event.mapPoint,
   *   updateLocationEnabled: true
   * });
   * @example
   * // Opens popup with the specified array of graphics and displays the
   * // features in a list (feature menu) at the location of the first graphic in the array.
   * view.openPopup({
   *   features: graphics,
   *   featureMenuOpen: true,
   *   location: graphics[0].geometry
   * });
   */
  openPopup(options?: ViewPopupOpenOptions): Promise<void>;
}

export type ViewPopupOpenOptions = Pick<PopupOpenOptions, "actions" | "content" | "features" | "fetchFeatures" | "location" | "promises" | "title" | "updateLocationEnabled">;

/**
 * Options for the [fetchPopupFeatures()](https://developers.arcgis.com/javascript/latest/references/core/views/PopupView/#fetchPopupFeatures) method. See properties below for object specifications.
 *
 * @since 5.1
 */
export interface FetchPopupFeaturesOptions extends AbortOptions {
  /**
   * The type of pointer coming from the input event.
   * It influences the tolerence when querying for features on services.
   * A `touch` pointer uses a larger tolerence than `mouse` or `pen`.
   */
  pointerType?: PointerType;
  /** A default popup template is automatically used if no `popupTemplate` is defined for a feature's origin */
  defaultPopupTemplateEnabled?: boolean;
}