import type Graphic from "../Graphic.js";
import type SpatialReference from "../geometry/SpatialReference.js";
import type Field from "../layers/support/Field.js";
import type Relationship from "../layers/support/Relationship.js";
import type Content from "./content/Content.js";
import type StatisticDefinition from "../rest/support/StatisticDefinition.js";
import type ActionButton from "../support/actions/ActionButton.js";
import type ActionToggle from "../support/actions/ActionToggle.js";
import type MapView from "../views/MapView.js";
import type SceneView from "../views/SceneView.js";
import type { ScreenPoint } from "../core/types.js";
import type { ClickEvent } from "../views/input/types.js";

/** @since 5.0 */
export type Alignment = PopupPositionValue | (() => PopupPositionValue);

/** @since 5.1 */
export type PopupAction = ActionButton | ActionToggle;

/** @since 5.1 */
export type InitialDisplayOptions = "list" | "feature";

/** @since 5.1 */
export interface PopupOpenOptions {}

/** @since 5.0 */
export interface DockOptions {
  /** Indicates whether the dock button is enabled. */
  buttonEnabled?: boolean;
  /** The position of the docked popup. */
  position?: PopupDockPosition;
  /** The breakpoint options for docking. */
  breakpoint?: DockOptionsBreakpoint | boolean;
}

/**
 * @since 5.0
 * @param width - The width breakpoint for docking.
 * @param height - The height breakpoint for docking.
 */
export interface DockOptionsBreakpoint {
  /** The width breakpoint for docking. */
  width?: number;
  /** The height breakpoint for docking. */
  height?: number;
}

/** @since 5.0 */
export interface FetchFeaturesOptions {
  /** The view click event that is passed into the fetchFeatures method. */
  event?: ClickEvent;
  /** An AbortSignal to cancel the fetch operation. */
  signal?: AbortSignal;
}

/** @since 5.0 */
export type PopupDockPosition = PopupPositionValue | (() => PopupPositionValue);

/** @since 5.0 */
export interface PopupOutsideViewOptions {
  /** The height of the popup. */
  popupHeight: number;
  /** The width of the popup. */
  popupWidth: number;
  /** The location on the screen where the popup is anchored. */
  screenLocation: ScreenPoint;
  /** The view in which the popup is displayed. */
  view: MapView | SceneView;
  /** The side of the view where the popup is located. */
  side: PopupOutsideViewSide;
}

/** @since 5.0 */
export type PopupOutsideViewSide = "bottom" | "left" | "right" | "top";

/** @since 5.0 */
export interface PopupPosition {
  /** The offset from the left edge of the screen. */
  left?: number;
  /** The offset from the top edge of the screen. */
  top?: number;
  /** The offset from the right edge of the screen. */
  right?: number;
  /** The offset from the bottom edge of the screen. */
  bottom?: number;
}

/** @since 5.0 */
export type PopupPositionResult = "bottom-center" | "bottom-left" | "bottom-right" | "top-center" | "top-left" | "top-right";

/** @since 5.0 */
export interface PopupPositionStyle {
  /** The offset from the left edge of the screen. */
  left?: string;
  /** The offset from the top edge of the screen. */
  top?: string;
  /** The offset from the right edge of the screen. */
  right?: string;
  /** The offset from the bottom edge of the screen. */
  bottom?: string;
}

/** @since 5.0 */
export type PopupPositionValue = PopupPositionResult | PopupPositionVariable;

/** @since 5.0 */
export type PopupPositionVariable = "auto" | "bottom-end" | "bottom-start" | "top-end" | "top-start";

/** @since 5.0 */
export type PopupTemplateContent = PopupTemplateContentResolved | PopupTemplateContentPromise | PopupTemplateContentFunction;

/**
 * Custom element content.
 *
 * @since 5.0
 */
export type PopupTemplateContentCreated = string | HTMLElement | null | undefined;

/** @since 5.0 */
export type PopupTemplateContentCreator = PopupTemplateContentCreatorFunction | PopupTemplateContentCreatorPromise | PopupTemplateContentCreated;

/**
 * The function that is called to create the custom content element.
 *
 * @param event - The event that contains the [Graphic](https://developers.arcgis.com/javascript/latest/references/core/Graphic/) used to represent the feature.
 * @returns The created custom content element.
 * @since 5.0
 */
export type PopupTemplateContentCreatorFunction = (event: PopupTemplateCreatorEvent) => PopupTemplateContentCreated | PopupTemplateContentCreatorPromise;

/** @since 5.0 */
export type PopupTemplateContentCreatorPromise = Promise<PopupTemplateContentCreated>;

/**
 * The function that is called to destroy the custom content element.
 *
 * @param event - The event that contains the [Graphic](https://developers.arcgis.com/javascript/latest/references/core/Graphic/) used to represent the feature.
 * @since 5.0
 */
export type PopupTemplateContentDestroyer = (event: PopupTemplateCreatorEvent) => void;

/**
 * @param event - The event that contains the [Graphic](https://developers.arcgis.com/javascript/latest/references/core/Graphic/) used to represent the feature.
 * @since 5.0
 */
export type PopupTemplateContentFunction = (event: PopupTemplateCreatorEvent) => PopupTemplateContentResolved | PopupTemplateContentPromise;

/** @since 5.0 */
export type PopupTemplateContentPromise = Promise<PopupTemplateContentResolved>;

/** @since 5.0 */
export type PopupTemplateContentResolved = PopupTemplateContentCreated | Content[];

/**
 * The event that contains the [Graphic](https://developers.arcgis.com/javascript/latest/references/core/Graphic/) used to represent the feature.
 *
 * @since 5.0
 */
export interface PopupTemplateCreatorEvent {
  /**
   * The [Graphic](https://developers.arcgis.com/javascript/latest/references/core/Graphic/) used to represent the feature.
   *
   * @since 5.0
   */
  graphic: Graphic;
}

/** @since 5.0 */
export type PopupTemplateTitle = PopupTemplateTitleResolved | PopupTemplateTitlePromise | PopupTemplateTitleFunction;

/**
 * @param event - The event that contains the [Graphic](https://developers.arcgis.com/javascript/latest/references/core/Graphic/) used to represent the feature.
 * @since 5.0
 */
export type PopupTemplateTitleFunction = (event: PopupTemplateCreatorEvent) => PopupTemplateTitleResolved | PopupTemplateTitlePromise;

/** @since 5.0 */
export type PopupTemplateTitlePromise = Promise<PopupTemplateTitleResolved>;

/** @since 5.0 */
export type PopupTemplateTitleResolved = string;

/** @since 5.0 */
export type State = "disabled" | "ready" | "error" | "loading";

/** @since 5.1 */
export interface FeatureFormattedAttributes {
  /**
   * The formatted attributes specified at the root level of the [PopupTemplate](https://developers.arcgis.com/javascript/latest/references/core/PopupTemplate/)
   * using the [PopupTemplate.fieldInfos](https://developers.arcgis.com/javascript/latest/references/core/PopupTemplate/#fieldInfos) property.
   *
   * @since 5.1
   */
  global: Record<string, any>;
  /**
   * The formatted attributes for an individual content element. This is derived from the
   * [PopupTemplate](https://developers.arcgis.com/javascript/latest/references/core/PopupTemplate/), or
   * per an individual content element. This element is defined with a [FieldsContent](https://developers.arcgis.com/javascript/latest/references/core/popup/content/FieldsContent/)
   * popup element set on the PopupTemplate's [PopupTemplate.content](https://developers.arcgis.com/javascript/latest/references/core/PopupTemplate/#content).
   *
   * @since 5.1
   */
  content: Record<string, any>[];
}

/** @since 5.1 */
export interface LastEditInfo {
  /**
   * User who performed the last edit on a feature.
   *
   * @since 5.1
   */
  user: string;
  /**
   * Date that the edit was performed.
   *
   * @since 5.1
   */
  date: string;
  /**
   * The type of edit that was performed on the feature.
   *
   * @since 5.1
   */
  type: "edit" | "create";
}

/**
 * Information about the layer associated with the feature.
 *
 * @since 5.1
 */
export interface LayerInfo {
  /**
   * An array of the layer's fields.
   *
   * @since 5.1
   */
  fields: Field[];
  /**
   * An array of the layer's relationships.
   *
   * @since 5.1
   */
  relationships: Relationship[];
  /**
   * The object ID field of the layer.
   *
   * @since 5.1
   */
  objectIdField: string;
  /**
   * Indicates whether the layer supports statistics.
   *
   * @since 5.1
   */
  supportsStatistics: boolean;
}

/** @since 5.1 */
export interface RelatedInfo {
  /**
   * The URL of the related layer.
   *
   * @since 5.1
   */
  url: string;
  /**
   * An array of statistics to be calculated for the related features.
   *
   * @since 5.1
   */
  outStatistics?: StatisticDefinition[];
  /**
   * An array of related fields that are related to the current feature.
   *
   * @since 5.1
   */
  relatedFields?: string[];
  /**
   * An array of features related to the current feature.
   *
   * @since 5.1
   */
  relatedFeatures?: Graphic[];
  /**
   * An array of related features with statistics for the current feature.
   *
   * @since 5.1
   */
  relatedStatsFeatures?: Graphic[];
  /**
   * The relationship between the current feature and the related features.
   *
   * @since 5.1
   */
  relation?: Relationship;
  /**
   * The layer information for the related features.
   *
   * @since 5.1
   */
  layerInfo?: LayerInfo;
  /**
   * The spatial reference of the source feature.
   *
   * @since 5.1
   */
  sourceSpatialReference?: SpatialReference;
}