import { Comparator, Direction, KeyOptions } from "./types-CdxsM0-q.js";

//#region src/order.d.ts

/**
 * Builder for immutable multi-step ordering rules.
 *
 * Create an `Order`, chain `.by()` calls to describe each step, then use
 * `.compare` with `Array.prototype.sort` or call `.sort()` for DSU-style sorting
 * that evaluates keys only once per step.
 *
 * @example
 * ```ts
 * const byStatusThenName = new Order<User>()
 * 	.by((u) => u.isActive, { direction: 'desc' })
 * 	.by((u) => u.lastName)
 * 	.by((u) => u.firstName);
 *
 * users.sort(byStatusThenName.compare);
 * ```
 */
declare class Order<T> {
  private _steps;
  /**
   * Create a new order. When a source or iterable of sources is provided, the
   * new order copies every step from the input.
   *
   * @example
   * ```ts
   * // Create an empty order and append steps to it:
   * const base = new Order<User>();
   * const byScore = base.by((u) => u.score);
   *
   * // Or combine multiple orders together:
   * const byScoreThenId = new Order([base, Order.by((u: User) => u.id)]);
   * ```
   */
  constructor();
  constructor(source: Order<T> | null | undefined);
  constructor(sources: Iterable<Order<T> | null | undefined>);
  /**
   * Create a new order with a single sort step.
   *
   * @example
   * ```ts
   * const byCreatedAt = Order.by((u: User) => u.createdAt, {
   * 	direction: 'desc',
   * });
   * ```
   */
  static by<T, K>(selectorFn: (item: T) => K, options?: KeyOptions<K, T>): Order<T>;
  /**
   * Append a sort step and return a new order instance.
   *
   * @example
   * ```ts
   * const byCreatedThenId = new Order<User>()
   * 	.by((u) => u.createdAt)
   * 	.by((u) => u.id);
   * ```
   */
  by<K>(selectorFn: (item: T) => K, options?: KeyOptions<K, T>): Order<T>;
  /**
   * Flip the direction of every step in an order.
   *
   * @example
   * ```ts
   * const newestFirst = Order.reverse(Order.by((u: User) => u.createdAt));
   * ```
   */
  static reverse<T>(input: Order<T>): Order<T>;
  /**
   * Flip the direction of every step in this order.
   *
   * @example
   * ```ts
   * const newestFirst = Order.by((u: User) => u.createdAt).reverse();
   * ```
   */
  reverse(): Order<T>;
  /**
   * Lifts an order defined for a derived or nested value into the parent domain.
   * The provided mapping function extracts the inner value, and the given order
   * is applied to that value when comparing parent items.
   *
   * @example
   * ```ts
   * interface Address {
   * 	city: string;
   * 	postcode: string;
   * }
   * interface Customer {
   * 	id: number;
   * 	address: Address;
   * }
   * const byAddress = Order.by((a: Address) => a.city).by((a) => a.postcode);
   * const byCustomerAddress = Order.map((c: Customer) => c.address, byAddress);
   * ```
   */
  static map<T, K>(outer: (t: T) => K, sub: Order<K>): Order<T>;
  /**
   * Appends additional sort steps that only apply when both compared items satisfy the given predicate.
   * If either item fails the predicate, the appended steps are skipped and sorting continues
   * with the next step in the current `Order`.
   *
   * @example
   * ```ts
   * const euPriority = Order.when(
   * 	(u: User) => u.region === 'eu',
   * 	Order.by((u: User) => u.score, { direction: 'desc' }),
   * );
   * ```
   */
  static when<T>(predicate: (value: T) => boolean, input: Order<T>): Order<T>;
  /**
   * Lifts an order defined for a derived or nested value into the parent domain.
   * The provided mapping function extracts the inner value, and the given order
   * is applied to that value when comparing parent items.
   *
   * @example
   * ```ts
   * interface Address {
   * 	city: string;
   * 	postcode: string;
   * }
   * interface Customer {
   * 	id: number;
   * 	address: Address;
   * }
   * const byIdThenAddress = new Order<Customer>()
   * 	.by((c) => c.id)
   * 	.map((c) => c.address, byAddress);
   * ```
   */
  map<K>(outer: (t: T) => K, sub: Order<K>): Order<T>;
  /**
   * Appends additional sort steps that only apply when both compared items satisfy the given predicate.
   * If either item fails the predicate, the appended steps are skipped and sorting continues
   * with the next step in the current `Order`.
   *
   * @example
   * ```ts
   * const byRegion = new Order<User>()
   * 	.by((u) => u.region)
   * 	.when(
   * 		(u) => u.region === 'eu',
   * 		Order.by((u) => u.score, { direction: 'desc' }),
   * 	)
   * 	// Append a final tiebreaker (runs for all items)
   *	.by((u) => u.id);
   * ```
   */
  when(predicate: (value: T) => boolean, order: Order<T>): Order<T>;
  /**
   * Retrieve a comparator compatible with `Array.prototype.sort`.
   *
   * @example
   * ```ts
   * users.sort(Order.by((u: User) => u.id).compare);
   * ```
   */
  get compare(): (a: T, b: T) => number;
  /**
   * Sort an array with the provided order and return a new array.
   *
   * This method implements the Schwartzian Transform or DSU
   * (decorate-sort-undecorate) technique, which ensures that each key
   * selector is only invoked once per element per step. For larger arrays or
   * costly key computations, this can yield significant performance
   * improvements over repeatedly calling the selector during comparisons.
   *
   * @example
   * ```ts
   * const out = Order.sort(users, Order.by((u: User) => u.lastName));
   * ```
   */
  static sort<T>(array: readonly T[], order: Order<T>): T[];
  /**
   * Sort an array with the provided order and return a new array.
   *
   * This method implements the Schwartzian Transform or DSU
   * (decorate-sort-undecorate) technique, which ensures that each key
   * selector is only invoked once per element per step. For larger arrays or
   * costly key computations, this can yield significant performance
   * improvements over repeatedly calling the selector during comparisons.
   *
   * @example
   * ```ts
   * const sorted = Order.by((u: User) => u.lastName).sort(users);
   * ```
   */
  sort(array: readonly T[]): T[];
  /** Replace the internal step list with provided steps. */
  private _assignSteps;
}
//#endregion
export { type Comparator, type Direction, type KeyOptions, Order };