/**
 * Lightweight deep equality check optimized for DataTable rows.
 * Compares arrays of row objects by first checking IDs (fast path),
 * then falling back to deep object comparison to handle nested structures.
 */
export function rowsEqual<T>(
  a: ReadonlyArray<T> | null,
  b: ReadonlyArray<T> | null,
): boolean;

/**
 * Returns true if the element's class list indicates the click target
 * is an overflow menu, checkbox, or radio button (row click should be ignored).
 */
export function shouldIgnoreRowClick(target: EventTarget | null): boolean;

/**
 * Resolves a nested property path in an object.
 * Supports both direct property access and nested paths like "contact.company".
 */
export function resolvePath<T extends Record<string, unknown>>(
  object: T,
  path: string,
): unknown;

/**
 * Paginates an array of rows based on page number and page size.
 */
export function getDisplayedRows<Row extends Record<string, unknown>>(
  rows: ReadonlyArray<Row>,
  page: number,
  pageSize: number,
): ReadonlyArray<Row>;

/**
 * Formats header width styles for table headers.
 * Combines width and minWidth into a CSS style string.
 */
export function formatHeaderWidth<
  Header extends {
    width?: string | null | number;
    minWidth?: string | null | number;
    [key: string]: unknown;
  } = {
    width?: string | null | number;
    minWidth?: string | null | number;
    [key: string]: unknown;
  },
>(header: Header): string | undefined;

/**
 * Compares two values for sorting in a data table.
 * Handles numbers, strings, null/undefined values, and custom sort functions.
 * @returns {number} Negative if a < b (ascending) or a > b (descending), positive if a > b (ascending) or a < b (descending), 0 if equal
 */
export function compareValues<T = unknown>(
  itemA: T,
  itemB: T,
  ascending: boolean,
  customSort?: ((a: T, b: T) => number) | false | undefined,
): number;

type PathDepth = [never, 0, 1, 2, ...0[]];

type Join<K, P> = K extends string | number
  ? P extends string | number
    ? `${K}${"" extends P ? "" : "."}${P}`
    : never
  : never;

/**
 * Drops string/number index signatures so `keyof` is only declared keys.
 * Used for paths on `DataTableRow` and subtypes, whose index signature would
 * otherwise widen `PropertyPath` to plain `string`.
 */
export type KeysWithoutIndexSignature<T> = {
  [K in keyof T as string extends K
    ? never
    : number extends K
      ? never
      : K]: T[K];
};

// For performance, the maximum traversal depth is 3.
export type PropertyPath<T, D extends number = 3> = [D] extends [never]
  ? never
  : T extends object
    ? {
        [K in keyof T]-?: K extends string | number
          ? `${K}` | Join<K, PropertyPath<T[K], PathDepth[D]>>
          : never;
      }[keyof T]
    : "";

/**
 * Like {@link PropertyPath}, but ignores string/number index signatures at
 * each object level so declared keys stay as literal unions (for `DataTableRow` subtypes).
 */
export type PropertyPathIgnoringIndexSignatures<T, D extends number = 3> = [
  D,
] extends [never]
  ? never
  : T extends object
    ? {
        [K in keyof KeysWithoutIndexSignature<T>]-?: K extends string | number
          ?
              | `${K}`
              | Join<
                  K,
                  PropertyPathIgnoringIndexSignatures<
                    KeysWithoutIndexSignature<T>[K],
                    PathDepth[D]
                  >
                >
          : never;
      }[keyof KeysWithoutIndexSignature<T>]
    : "";

/**
 * Cell value type at a column path (e.g. `"port"` or `"contact.company"`).
 */
export type DataTableValueAtPath<Row, Path extends string> = Row extends object
  ? Path extends keyof Row & string
    ? Row[Path]
    : Path extends `${infer Head}.${infer Rest}`
      ? Head extends keyof Row
        ? DataTableValueAtPath<NonNullable<Row[Head]>, Rest>
        : unknown
      : unknown
  : unknown;

/**
 * Union of cell value types for all column paths on `Row`.
 * Used for default and per-column `sort` comparators.
 *
 * `Row` is unconstrained so generated `DataTableSortValue<Row = DataTableRow>` aliases stay valid;
 * non-object `Row` resolves to `never`.
 */
export type DataTableSortValue<Row> = Row extends object
  ? PropertyPath<Row> extends infer K
    ? K extends string
      ? DataTableValueAtPath<Row, K>
      : never
    : never
  : never;
