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

export interface BinParametersBaseProperties extends 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;
}

/**
 * Specifies the expected data type of the output from the [expression](https://developers.arcgis.com/javascript/latest/references/core/rest/support/BinParametersBase/#expression), based on the type of value the expression generates.
 * The [expression](https://developers.arcgis.com/javascript/latest/references/core/rest/support/BinParametersBase/#expression) property must be set when this property is set.
 *
 * @see [expressionValueType](https://developers.arcgis.com/javascript/latest/references/core/rest/support/BinParametersBase/#expressionValueType)
 */
export type BinParameterFieldType = "small-integer" | "integer" | "single" | "double" | "long" | "date" | "date-only" | "time-only" | "timestamp-offset";

/**
 * A mixin that provides common binning parameters to [AutoIntervalBinParameters](https://developers.arcgis.com/javascript/latest/references/core/rest/support/AutoIntervalBinParameters/), [DateBinParameters](https://developers.arcgis.com/javascript/latest/references/core/rest/support/DateBinParameters/),
 * [FixedBoundariesBinParameters](https://developers.arcgis.com/javascript/latest/references/core/rest/support/FixedBoundariesBinParameters/), and [FixedIntervalBinParameters](https://developers.arcgis.com/javascript/latest/references/core/rest/support/FixedIntervalBinParameters/).
 *
 * @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/references/core/rest/support/BinParametersBase/#field). The specified SQL expression must evaluate to a numeric or date type.
   * Both [field](https://developers.arcgis.com/javascript/latest/references/core/rest/support/BinParametersBase/#field) and the `expression` cannot be specified for the same bin. The [expressionValueType](https://developers.arcgis.com/javascript/latest/references/core/rest/support/BinParametersBase/#expressionValueType) property must be set to the expected data type
   * of the output from the expression.
   *
   * @see [expressionValueType](https://developers.arcgis.com/javascript/latest/references/core/rest/support/BinParametersBase/#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/references/core/rest/support/BinParametersBase/#expression), based on the type of value the expression generates.
   * The [expression](https://developers.arcgis.com/javascript/latest/references/core/rest/support/BinParametersBase/#expression) property must be set when this property is set.
   *
   * @see [expression](https://developers.arcgis.com/javascript/latest/references/core/rest/support/BinParametersBase/#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?: BinParameterFieldType | null;
  /**
   * The field name used to calculate the bins. The [expression](https://developers.arcgis.com/javascript/latest/references/core/rest/support/BinParametersBase/#expression) property cannot be set when this property is set.
   *
   * @see [expression](https://developers.arcgis.com/javascript/latest/references/core/rest/support/BinParametersBase/#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.
   */
  accessor firstDayOfWeek: number | null | undefined;
  /** If `true`, the  `upperBoundary` and `bin` fields will not be included in the attributes. */
  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