import type AttributeBinsGrouping from "./AttributeBinsGrouping.js";
import type { ClonableMixin, ClonableMixinProperties } from "../../core/Clonable.js";
import type { JSONSupport, JSONSupportMixinProperties } from "../../core/JSONSupport.js";
import type { AttributeBinsGroupingProperties } from "./AttributeBinsGrouping.js";

export interface BinParametersBaseProperties extends JSONSupportMixinProperties, ClonableMixinProperties, Partial<Pick<BinParametersBase, "expression" | "expressionValueType" | "field" | "firstDayOfWeek" | "hideUpperBound">> {
  /**
   * The `splitBy` parameter divides data into separate bins for each unique value in the categorical field. Each category will have different bin boundaries based on the data distribution within that category.
   * For example, when analyzing sales by region (e.g., Central, Northeast, etc.), `splitBy` will create separate bin ranges for each region, allowing the boundaries to adjust to the specific data distribution of each region.
   * The `splitBy` parameter is useful when the distribution of values within each category (e.g., branch or region) differs significantly, and you want each category’s binning to reflect its unique data range.
   *
   * > [!WARNING]
   * >
   * > Field with many unique values are not appropriate for splitting bins into multiple series.
   *
   * @example
   * // create bins based on the SalesTotal field, split by the Branch field.
   * const binQuery = new AttributeBinsQuery({
   *   binParameters: new AutoIntervalBinParameters({
   *     numBins: 5, // the interval size for each bin
   *     field: "SalesTotal",
   *     splitBy: { // autocasts to AttributeBinsGrouping
   *       type: "field",
   *       value: "Branch"
   *     }
   *   })
   * });
   * const result = await layer.queryAttributeBins(binQuery);
   */
  splitBy?: AttributeBinsGroupingProperties | null;
  /**
   * The `stackBy` parameter divides each bin into segments based on unique values from a categorical field, allowing you to compare multiple categories within the same bin
   * while keeping the bin boundaries consistent across all categories. This enables you to visualize or analyze the distribution of categories stacked together within the same range of values.
   * For example, with 3 bins based on total sales with ranges like $0 to $5000, $5001 to $10,000, and $10,001 to $15,000, setting `stackBy = SalesRep` will stack each sales rep's contribution
   * within the same bin range. The bin boundaries remain the same, and each segment within the bin shows how individual categories contribute to the total frequency or value.
   *
   * > [!WARNING]
   * >
   * > Field with many unique values are not appropriate for splitting bins into multiple series.
   *
   * @example
   * // create bins based on the SalesTotal field, stacked by the Month field.
   * const binQuery = new AttributeBinsQuery({
   *   binParameters: new AutoIntervalBinParameters({
   *     numBins: 5, // the interval size for each bin
   *     field: "SalesTotal",
   *     stackBy: {
   *       value: "EXTRACT(MONTH from invoiceDate)",
   *       type: "expression",
   *       valueType: "double",
   *       alias: "Month"
   *     }
   *   })
   * });
   * const result = await layer.queryAttributeBins(binQuery);
   */
  stackBy?: AttributeBinsGroupingProperties | null;
}

export type BinParameterFiledType = "small-integer" | "integer" | "single" | "double" | "long" | "date" | "date-only" | "time-only" | "timestamp-offset";

/**
 * Mixin for binning parameters.
 *
 * @since 4.32
 */
export default abstract class BinParametersBase extends BinParametersBaseSuperclass {
  /**
   * A standardized SQL expression used to calculate the bins, rather than referencing a [field](https://developers.arcgis.com/javascript/latest/api-reference/esri-rest-support-BinParametersBase.html#field). The specified SQL expression must evaluate to a numeric or date type.
   * Both [field](https://developers.arcgis.com/javascript/latest/api-reference/esri-rest-support-BinParametersBase.html#field) and the `expression` cannot be specified for the same bin. The [expressionValueType](https://developers.arcgis.com/javascript/latest/api-reference/esri-rest-support-BinParametersBase.html#expressionValueType) property must be set to the expected data type
   * of the output from the expression.
   *
   * > [!WARNING]
   * >
   * > **Known Limitations**
   * >
   * >  The `expression` is only supported with server-side [FeatureLayers](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-FeatureLayer.html).
   *
   * @see [expressionValueType](https://developers.arcgis.com/javascript/latest/api-reference/esri-rest-support-BinParametersBase.html#expressionValueType)
   * @example
   * const binQuery = new AttributeBinsQuery({
   *   binParameters: new AutoIntervalBinParameters({
   *     numBins: 5, // the interval size for each bin
   *     // sql expression to calculate the bins based on the product of Quantity and SalesAmount
   *     expression: "Quantity * SalesAmount"
   *     expressionValueType: "double"
   *   })
   * });
   */
  accessor expression: string | null | undefined;
  /**
   * Specifies the expected data type of the output from the [expression](https://developers.arcgis.com/javascript/latest/api-reference/esri-rest-support-BinParametersBase.html#expression), based on the type of value the expression generates.
   * The [expression](https://developers.arcgis.com/javascript/latest/api-reference/esri-rest-support-BinParametersBase.html#expression) property must be set when this property is set.
   *
   * > [!WARNING]
   * >
   * > **Known Limitations**
   * >
   * >  The `expressionValueType` is only supported with server-side [FeatureLayers](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-FeatureLayer.html).
   *
   * @see [expression](https://developers.arcgis.com/javascript/latest/api-reference/esri-rest-support-BinParametersBase.html#expression)
   * @example
   * const binQuery = new AttributeBinsQuery({
   *   binParameters: new AutoIntervalBinParameters({
   *     numBins: 5, // the interval size for each bin
   *     // sql expression to calculate the bins based on the product of Quantity and SalesAmount
   *     expression: "Quantity * SalesAmount"
   *     expressionValueType: "double"
   *   })
   * });
   */
  expressionValueType?: BinParameterFiledType | null;
  /**
   * The field name used to calculate the bins. The [expression](https://developers.arcgis.com/javascript/latest/api-reference/esri-rest-support-BinParametersBase.html#expression) property cannot be set when this property is set.
   *
   * @see [expression](https://developers.arcgis.com/javascript/latest/api-reference/esri-rest-support-BinParametersBase.html#expression)
   */
  accessor field: string | null | undefined;
  /**
   * The first day of the week. This property is used to determine the start of the week for date-based bins.
   * The default value is 7, representing Sunday, if no value is specified.
   *
   * > [!WARNING]
   * >
   * > **Known Limitations**
   * >
   * >  The `firstDayOfWeek` is only supported with server-side [FeatureLayers](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-FeatureLayer.html).
   */
  accessor firstDayOfWeek: number | null | undefined;
  /**
   * If `true`, the  `upperBoundary` and `bin` fields will not be included in the attributes.
   *
   * > [!WARNING]
   * >
   * > **Known Limitations**
   * >
   * >  The `hideUpperBound` is only supported with server-side [FeatureLayers](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-FeatureLayer.html).
   */
  accessor hideUpperBound: boolean | null | undefined;
  /**
   * The `splitBy` parameter divides data into separate bins for each unique value in the categorical field. Each category will have different bin boundaries based on the data distribution within that category.
   * For example, when analyzing sales by region (e.g., Central, Northeast, etc.), `splitBy` will create separate bin ranges for each region, allowing the boundaries to adjust to the specific data distribution of each region.
   * The `splitBy` parameter is useful when the distribution of values within each category (e.g., branch or region) differs significantly, and you want each category’s binning to reflect its unique data range.
   *
   * > [!WARNING]
   * >
   * > Field with many unique values are not appropriate for splitting bins into multiple series.
   *
   * @example
   * // create bins based on the SalesTotal field, split by the Branch field.
   * const binQuery = new AttributeBinsQuery({
   *   binParameters: new AutoIntervalBinParameters({
   *     numBins: 5, // the interval size for each bin
   *     field: "SalesTotal",
   *     splitBy: { // autocasts to AttributeBinsGrouping
   *       type: "field",
   *       value: "Branch"
   *     }
   *   })
   * });
   * const result = await layer.queryAttributeBins(binQuery);
   */
  get splitBy(): AttributeBinsGrouping | null | undefined;
  set splitBy(value: AttributeBinsGroupingProperties | null | undefined);
  /**
   * The `stackBy` parameter divides each bin into segments based on unique values from a categorical field, allowing you to compare multiple categories within the same bin
   * while keeping the bin boundaries consistent across all categories. This enables you to visualize or analyze the distribution of categories stacked together within the same range of values.
   * For example, with 3 bins based on total sales with ranges like $0 to $5000, $5001 to $10,000, and $10,001 to $15,000, setting `stackBy = SalesRep` will stack each sales rep's contribution
   * within the same bin range. The bin boundaries remain the same, and each segment within the bin shows how individual categories contribute to the total frequency or value.
   *
   * > [!WARNING]
   * >
   * > Field with many unique values are not appropriate for splitting bins into multiple series.
   *
   * @example
   * // create bins based on the SalesTotal field, stacked by the Month field.
   * const binQuery = new AttributeBinsQuery({
   *   binParameters: new AutoIntervalBinParameters({
   *     numBins: 5, // the interval size for each bin
   *     field: "SalesTotal",
   *     stackBy: {
   *       value: "EXTRACT(MONTH from invoiceDate)",
   *       type: "expression",
   *       valueType: "double",
   *       alias: "Month"
   *     }
   *   })
   * });
   * const result = await layer.queryAttributeBins(binQuery);
   */
  get stackBy(): AttributeBinsGrouping | null | undefined;
  set stackBy(value: AttributeBinsGroupingProperties | null | undefined);
}
declare const BinParametersBaseSuperclass: typeof JSONSupport & typeof ClonableMixin