import type { JSONSupport } from "../core/JSONSupport.js";
import type { TimeUnit } from "../core/units.js";
import type { TimeZone } from "./types.js";

export interface TimeExtentProperties {
  /** The end time of the time extent. */
  end?: (Date | number | string) | null;
  /** The start time of the time extent. */
  start?: (Date | number | string) | null;
}

/**
 * A period of time with a definitive [start](https://developers.arcgis.com/javascript/latest/references/core/time/TimeExtent/#start) and [end](https://developers.arcgis.com/javascript/latest/references/core/time/TimeExtent/#end) date. Time extent is used to
 * [FeatureLayerView.filter](https://developers.arcgis.com/javascript/latest/references/core/views/layers/FeatureLayerView/#filter) or
 * [query](https://developers.arcgis.com/javascript/latest/references/core/views/layers/FeatureLayerView/#queryFeatures) features that fall within the specified time period.
 * To represent an instant of time, set the [start](https://developers.arcgis.com/javascript/latest/references/core/time/TimeExtent/#start) and [end](https://developers.arcgis.com/javascript/latest/references/core/time/TimeExtent/#end) times to the same date.
 *
 * When creating a [JavaScript Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date),
 * be mindful that most constructors will create a date with respect to your local timezone rather than
 * [UTC](https://en.wikipedia.org/wiki/Coordinated_Universal_Time) (i.e. universal time). To create a date with
 * respect to UTC, use the [UTC method](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/UTC)
 * on the Date object.
 *
 * @since 4.31
 * @example
 * // Represents the data for the month of Jan, 1970
 * const timeExtent = new TimeExtent({
 *   start: new Date(Date.UTC(1970, 0, 1, 6, 30)),
 *   end: new Date(Date.UTC(1970, 0, 31, 6, 30))
 * });
 */
export default class TimeExtent extends JSONSupport {
  /**
   * @example
   * // Typical usage
   * // Represents the data for the month of Jan, 1970
   * const timeExtent = new TimeExtent({
   *   start: new Date(Date.UTC(1970, 0, 1, 6, 30)),
   *   end: new Date(Date.UTC(1970, 0, 31, 6, 30))
   * });
   */
  constructor(properties?: TimeExtentProperties);
  /** The end time of the time extent. */
  get end(): Date | null | undefined;
  set end(value: (Date | number | string) | null | undefined);
  /** The start time of the time extent. */
  get start(): Date | null | undefined;
  set start(value: (Date | number | string) | null | undefined);
  /**
   * Creates a deep clone of TimeExtent object.
   *
   * @returns A new instance of a TimeExtent object equal to the object used to call `.clone()`.
   */
  clone(): TimeExtent;
  /**
   * Expands the TimeExtent so that the start and end dates are rounded down and up, respectively, to the parsed time unit.
   *
   * @param unit - The time unit to align the start and end dates.
   * @param timeZone - The time zone in which progressing will occur. The default is "system".
   * @returns A new expanded TimeExtent.
   * @see [Sample - Time Slider component](https://developers.arcgis.com/javascript/latest/sample-code/timeslider/)
   * @example
   * // Expand a time extent to a decade.
   * const extent = new TimeExtent({
   *   start: new Date(2012, 3, 5),
   *   end: new Date(2019, 0, 4)
   * });
   * const decade = extent.expandTo("decades");
   * // decade is: 1/1/2010 to 1/1/2020
   * @example
   * // Expand a time extent to the nearest month.
   * const extent = new TimeExtent({
   *   start: new Date(2012, 3, 5),
   *   end: new Date(2019, 0, 4)
   * });
   * const expandToMonth = extent.expandTo("months");
   * // expandToMonth is: 4/1/2012 to 2/1/2019
   */
  expandTo(unit: TimeUnit, timeZone?: TimeZone): TimeExtent;
  /**
   * Returns the time extent resulting from the intersection of a given time extent and
   * parsed time extent. Returns a timeExtent with `undefined` values for [start](https://developers.arcgis.com/javascript/latest/references/core/time/TimeExtent/#start)
   * and [end](https://developers.arcgis.com/javascript/latest/references/core/time/TimeExtent/#end) properties if the two time extents do not intersect.
   *
   * @param timeExtent - The time extent to be intersected with the time extent
   * on which `intersection()` is being called on.
   * @returns The intersecting time extent between two time extents.
   * @example
   * // get the intersecting timeExtent between view.timeExtent and
   * // layer view filter's timeExtent
   * const timeExtent = view.timeExtent.intersection(layerView.effect.filter.timeExtent);
   * if (timeExtent){
   *   console.log("time intersection", timeExtent);
   *   const query = layerView.createQuery();
   *   query.timeExtent = timeExtent;
   *   layerView.queryFeatures(query).then(function(results){
   *     console.log(results.features.length, " are returned for intersecting timeExtent");
   *   });
   * }
   */
  intersection(timeExtent: TimeExtent | null | undefined): TimeExtent;
  /**
   * Returns the time extent resulting from the union of the current time extent and a given time extent.
   *
   * @param timeExtent - The time extent to be unioned with.
   * @returns The resulting union of the current time extent and the given time extent.
   * @example
   * // Return the union of two time extents. One from 1990 to 2000 and the second from 2010 to 2020.
   * const decade1 = new TimeExtent({
   *   start: new Date(1990, 0, 1),
   *   end: new Date(2000, 0, 1)
   * });
   * const decade2 = new TimeExtent({
   *   start: new Date(2010, 0, 1),
   *   end: new Date(2020, 0, 1)
   * });
   * const union = decade1.union(decade2);
   * console.log(`The unioned extent starts from year ${union.start.getFullYear()} to ${union.end.getFullYear()}`);
   * // output: "The unioned extent starts from year 1990 to 2020"
   */
  union(timeExtent: TimeExtent | null | undefined): TimeExtent;
}