import { HTMLAttributes, ReactNode } from 'react';
import { VariableSizeList as List } from 'react-window';
export type ColumnKey = string;
export type TextAlign = "start" | "center" | "end";
/** Cross-axis alignment for body cells (`BodyCell` flex `align-items`). */
export type CellVerticalAlign = "start" | "center" | "stretch";
export type SortDirection = "asc" | "desc";
export interface SortState {
    columnKey: ColumnKey;
    direction: SortDirection;
}
export interface RenderHeaderArgs<TData> {
    column: ColumnDef<TData>;
    columnIndex: number;
    sortState: SortState | null;
    onSortClick: () => void;
}
export interface RenderCellArgs<TData> {
    column: ColumnDef<TData>;
    columnIndex: number;
    isHovered: boolean;
    row: TData;
    rowIndex: number;
    /** When true, first *data* column cell can render empty (group continuation). */
    rowMeta?: DataListTableRowMeta;
}
export interface DataListTableRowMeta {
    hideFirstDataColumn?: boolean;
}
export interface ColumnDef<TData = unknown> {
    header: ReactNode | ((args: RenderHeaderArgs<TData>) => ReactNode);
    key: ColumnKey;
    /** Minimum width in px */
    minWidth: number;
    align?: TextAlign;
    /** Optional body cell background when the cell is not sticky (CSS). */
    cellBackground?: string;
    /** Optional body cell text color (CSS); when omitted, inherits row hover/selection color. */
    cellColor?: string;
    /** Override the default body cell padding (CSS shorthand, e.g. "8px 16px 8px 64px"). */
    cellPadding?: string;
    /** Optional body cell background when sticky (CSS). */
    cellStickyBackground?: string;
    /**
     * Per-column cross-axis alignment for body cells; overrides table `cellVerticalAlign` when set.
     */
    cellVerticalAlign?: CellVerticalAlign;
    /** Optional header cell background (CSS). */
    headerBackground?: string;
    /** Optional header cell text color (CSS color string / theme token). */
    headerColor?: string;
    /** Override the default header cell padding (CSS shorthand, e.g. "8px 16px 8px 64px"). */
    headerPadding?: string;
    lineClamp?: number;
    /** Hard max on column def; combined with `maxWidthByColumnKey` on table */
    maxWidth?: number;
    /** When true, show a sort indicator even if `sortable` is false. Defaults to `sortable`. */
    showSortIndicator?: boolean;
    sortable?: boolean;
    /** Sticky on the left within the scroll area (after optional rails). */
    sticky?: boolean;
    visible?: boolean;
    /**
     * When `DataListTable` `isResponsiveTable` is true, share of the **data** area width (0–100).
     * Values are normalized to sum to 100% across visible columns. Omitted columns count as 0;
     * if the total is 0, columns split evenly.
     */
    widthPercent?: number;
    renderCell: (args: RenderCellArgs<TData>) => ReactNode;
    getSortValue?: (row: TData) => unknown;
    renderHeader?: (args: RenderHeaderArgs<TData>) => ReactNode;
}
export interface DataListTableFeatures {
    checkboxRail?: boolean;
    columnReorder?: boolean;
    rowComment?: boolean;
    rowMenu?: boolean;
}
export interface DataListTableInfiniteConfig {
    /** Total items server says exist (may be > data.length while loading). */
    itemCount: number;
    isItemLoaded: (index: number) => boolean;
    loadMoreItems: (startIndex: number, stopIndex: number) => Promise<void> | void;
    /** Replaces default "…" placeholder when `isItemLoaded(index)` is false. */
    renderPlaceholderRow?: (index: number) => ReactNode;
}
export interface DataListTableProps<TData> {
    /** Display order; must be a permutation of visible column keys (extras ignored). */
    columnOrder: ColumnKey[];
    columns: ColumnDef<TData>[];
    data: TData[];
    /** Fixed height for table body area; omit with `fillParent` to use AutoSizer. */
    bodyHeight?: number;
    /**
     * When true, `bodyHeight` already accounts for the sticky header band, so
     * `DATA_LIST_TABLE_HEADER_OVERHEAD_PX` is not added to `rootHeight` or
     * `fillWrapperHeight`.
     */
    bodyHeightIncludesHeader?: boolean;
    /**
     * Vertical alignment of content inside each body cell.
     * @default "start"
     */
    cellVerticalAlign?: CellVerticalAlign;
    /**
     * When true (default), if total min column width is less than the measured viewport width,
     * the table frame is centered with equal space on both sides. When false, the frame stays
     * left-aligned (e.g. compressed side-panel layout).
     * @default true
     */
    centerWhenNarrow?: boolean;
    className?: string;
    /**
     * When `isResponsiveTable` is true, horizontal gap (px) between adjacent data columns.
     * Subtracted from the data area before width allocation so columns + gaps fit the viewport.
     * When set, `DataListTable` also applies this as CSS `gap` on header, body, and placeholder rows
     * so layout math matches rendering (consumers should not duplicate via host `!important` rules).
     */
    columnGapPx?: number;
    "data-testid"?: string;
    /**
     * When true, sets `overflow: hidden` on the react-window List to suppress internal
     * scrollbars. Use with content-height mode where the outer page handles scrolling.
     */
    disableInternalScroll?: boolean;
    /** Default height when a row has not been measured yet. */
    estimatedRowHeight?: number;
    /**
     * When true, if the measured width is at least the table’s minimum column width, the
     * list frame uses the full measured width instead of capping at the min column sum. Use
     * for full-bleed page tables so consumers do not need CSS overrides on the AutoSizer
     * wrapper. Narrower viewports still use `Math.min(measured, min)` so horizontal scroll
     * behavior is unchanged.
     * @default false
     */
    expandFrameWidthToViewport?: boolean;
    features?: DataListTableFeatures;
    /** Parent must have definite height; uses AutoSizer for body. */
    fillParent?: boolean;
    infiniteLoader?: DataListTableInfiniteConfig;
    /** Initial vertical scroll offset for the virtual list (scroll restore). */
    initialScrollOffset?: number;
    /**
     * Only when `isResponsiveTable` is true. If true or omitted, when the viewport is narrower than
     * `responsiveTableMinWidth`, columns use fixed `minWidth` px and the table scrolls horizontally.
     * If false, the table stays fluid: percent widths apply to the actual viewport width (no min-width
     * scroll shell). Ignored when `isResponsiveTable` is false.
     * @default true
     */
    isHorizontalScroll?: boolean;
    /**
     * When true, column widths follow `widthPercent` on each column over the **data** area;
     * overall table width is clamped between `responsiveTableMinWidth` and `responsiveTableMaxWidth`.
     * When the viewport is narrower than the minimum, behavior depends on `isHorizontalScroll`
     * (default: fixed `minWidth` columns + horizontal scroll). When false or omitted, behavior
     * matches the legacy fixed layout.
     * @default false
     */
    isResponsiveTable?: boolean;
    maxWidthByColumnKey?: Partial<Record<ColumnKey, number>>;
    /**
     * Spread onto the default infinite-loader placeholder row root (the flex row). Use for
     * `data-*` or `className` when host styling must target skeleton rows without
     * `infiniteLoader.renderPlaceholderRow`.
     */
    placeholderRowRootProps?: HTMLAttributes<HTMLDivElement>;
    /**
     * Maximum width (px) of the full table row. When omitted, no upper cap (only viewport and min apply).
     */
    responsiveTableMaxWidth?: number;
    /**
     * Minimum width (px) of the full table row (data columns + feature rails). Defaults to the
     * sum of column `minWidth`s plus rails when omitted.
     */
    responsiveTableMinWidth?: number;
    /** Bump to force row remeasure without changing row id. */
    rowLayoutVersion?: number;
    /**
     * Minimum height of each body row in px.
     * @default 48
     */
    rowMinHeight?: number;
    /** Controlled selection (row ids). */
    selectedRowIds?: ReadonlySet<string> | string[];
    /**
     * When false, no outer frame is drawn (for embedding inside a card that already has a border).
     * @default true
     */
    showOuterBorder?: boolean;
    sortState?: SortState | null;
    /** Keys that stick left; can also set `sticky` on column def. */
    stickyColumnKeys?: ColumnKey[];
    getRowId: (row: TData, index: number) => string;
    /**
     * Per-row height estimate for `VariableSizeList` before DOM measure (react-window `itemSize`).
     * Use when row height varies (e.g. stacked line items). Falls back to `estimatedRowHeight`.
     */
    getEstimatedRowHeight?: (index: number) => number;
    /** Optional row metadata for grouped / split rows (first column continuation). */
    getRowMeta?: (row: TData, index: number) => DataListTableRowMeta | undefined;
    onColumnOrderChange?: (nextOrder: ColumnKey[]) => void;
    onScroll?: (scrollOffset: number) => void;
    onSelectedRowIdsChange?: (ids: Set<string>) => void;
    onSortChange?: (next: SortState | null) => void;
    /** Receives the react-window `VariableSizeList` used for the main scroll pane (body rows). */
    onVirtualListRef?: (instance: List | null) => void;
    /**
     * When `features.checkboxRail` is used, replaces the default native checkbox in each row
     * (e.g. controlled selection with custom checkbox UI).
     */
    renderCheckboxRailCell?: (row: TData, rowIndex: number) => ReactNode;
    /** Replaces the default “select all” control in the checkbox rail header. */
    renderCheckboxRailHeader?: () => ReactNode;
    /**
     * Renders a footer row **below** the bordered table frame (outside the rounded border) while
     * staying **horizontally aligned** with the grid (synced to the list’s horizontal scroll).
     */
    renderFooterBelowFrame?: () => ReactNode;
    /** Icon rendered on the right border edge of each row (e.g. comment count badge). */
    renderRowBorderIcon?: (row: TData, rowIndex: number) => ReactNode;
    renderRowComment?: (row: TData, rowIndex: number) => ReactNode;
    /** Label for the row-comment rail header when `features.rowComment` is true (default empty). */
    renderRowCommentHeader?: () => ReactNode;
    renderRowMenu?: (row: TData, rowIndex: number) => ReactNode;
}
