import { ReactNode } from 'react';
import { BooleanFormatterOptions, CurrencyFormatterOptions, DateFormatterOptions, DateTimeFormatterOptions, NumberFormatterOptions, PercentFormatterOptions, TimeFormatterOptions } from './formatters';
import { SelectMenuOption, SelectMenuGroupByValue } from '../SelectMenu';
import { SelectMenuSyncProps } from '../SelectMenu/SelectMenuSync';
import { SelectMenuProps } from '../SelectMenu/types';
import { MultiSelectMenuOption } from '../MultiSelectMenu';
import { MultiSelectMenuSyncProps } from '../MultiSelectMenu/MultiSelectMenuSync';
import { MultiSelectMenuProps } from '../MultiSelectMenu/types';
/**
 * Column type literals for display configuration.
 * Each type maps to a default formatter and alignment.
 */
export type ColumnType = "text" | "number" | "currency" | "percent" | "date" | "dateTime" | "time" | "boolean" | "markdown" | "html";
/**
 * Maps column types to their formatter options.
 * Used for type-safe formatter configuration.
 */
export type ColumnTypeOptionsMap = {
    text: undefined;
    number: NumberFormatterOptions;
    currency: CurrencyFormatterOptions;
    percent: PercentFormatterOptions;
    date: DateFormatterOptions;
    dateTime: DateTimeFormatterOptions;
    time: TimeFormatterOptions;
    boolean: BooleanFormatterOptions;
    markdown: undefined;
    html: undefined;
};
/**
 * Column type configuration.
 * Can be a simple type string (uses defaults) or an object with custom options.
 *
 * @example
 * ```ts
 * // Simple - uses default formatter options
 * type: "currency"
 *
 * // With options - customizes formatter behavior
 * type: { type: "currency", options: { currency: "EUR", locale: "de-DE" } }
 * ```
 */
export type ColumnTypeConfig<T extends ColumnType = ColumnType> = T | {
    type: T;
    options: ColumnTypeOptionsMap[T];
};
/**
 * Edit mode literals for editable cells.
 */
export type EditMode = "text" | "number" | "select" | "select-async" | "multiselect" | "multiselect-async" | "boolean";
/**
 * Base edit configuration shared by all edit modes.
 * @template T - The row data type
 * @template K - The column key
 */
type BaseEditConfig<T, K extends keyof T> = {
    /**
     * Callback fired when the cell value is saved.
     * @param value - The new value
     * @param rowId - The id of the row being edited
     */
    onChange: (value: T[K], rowId: string) => void;
};
/**
 * Edit configuration for text mode cells.
 * @template T - The row data type
 * @template K - The column key
 */
export type TextEditConfig<T, K extends keyof T> = BaseEditConfig<T, K> & {
    /**
     * Text edit mode - renders an inline text input.
     */
    mode: "text";
};
/**
 * Edit configuration for number mode cells.
 * Renders an inline number input with increment/decrement support.
 *
 * @template T - The row data type
 * @template K - The column key
 */
export type NumberEditConfig<T, K extends keyof T> = BaseEditConfig<T, K> & {
    /**
     * Number edit mode - renders an inline number input with formatting and validation.
     */
    mode: "number";
    /**
     * The minimum value for the number field.
     * @default 0
     */
    minValue?: number;
    /**
     * The maximum value for the number field.
     * @default 100000000000000
     */
    maxValue?: number;
    /**
     * The step value for the number field.
     * @default 1
     */
    step?: number;
    /**
     * The maximum number of decimal places for the number field.
     * @default 0
     */
    maximumFractionDigits?: number;
    /**
     * The minimum number of decimal places for the number field.
     * @default 0
     */
    minimumFractionDigits?: number;
};
type SelectMenuCellPassthroughProps = Omit<SelectMenuSyncProps, "trigger" | "label" | "value" | "onSelectedOptionChange" | "options" | "onMenuKeyDown" | "onImplicitClose" | "onExplicitClose">;
type MultiSelectMenuCellPassthroughProps = Omit<MultiSelectMenuSyncProps, "trigger" | "label" | "value" | "onSelectedOptionsChange" | "options" | "onMenuKeyDown" | "onImplicitClose" | "onExplicitClose">;
/**
 * Edit configuration for select mode cells.
 * @template T - The row data type
 * @template K - The column key
 */
export type SelectEditConfig<T, K extends keyof T> = Omit<BaseEditConfig<T, K>, "onChange"> & {
    /**
     * Select edit mode - renders a SelectMenu popover.
     */
    mode: "select";
    /**
     * The options available for selection.
     */
    options: SelectMenuOption[];
    /**
     * Callback fired when the selected option changes.
     * @param option - The newly selected option, or null if cleared
     * @param rowId - The id of the row being edited
     */
    onChange: (option: SelectMenuOption | null, rowId: string) => void;
} & SelectMenuCellPassthroughProps;
/**
 * Edit configuration for multiselect mode cells.
 * @template T - The row data type
 * @template K - The column key
 */
export type MultiselectEditConfig<T, K extends keyof T> = Omit<BaseEditConfig<T, K>, "onChange"> & {
    /**
     * Multiselect edit mode - renders a searchable MultiSelectMenu popover.
     */
    mode: "multiselect";
    /**
     * The options available for selection.
     */
    options: MultiSelectMenuOption[];
    /**
     * Callback fired when the selected options change.
     * @param options - The newly selected options
     * @param rowId - The id of the row being edited
     */
    onChange: (options: MultiSelectMenuOption[], rowId: string) => void;
} & MultiSelectMenuCellPassthroughProps;
type SelectMenuAsyncCellPassthroughProps = Omit<SelectMenuProps, "trigger" | "label" | "value" | "onSelectedOptionChange" | "loadOptions" | "lazy" | "lazyOptions" | "onMenuKeyDown" | "onImplicitClose" | "onExplicitClose">;
type MultiSelectMenuAsyncCellPassthroughProps = Omit<MultiSelectMenuProps, "trigger" | "label" | "value" | "onSelectedOptionsChange" | "loadOptions" | "lazy" | "lazyOptions" | "onMenuKeyDown" | "onImplicitClose" | "onExplicitClose">;
/**
 * Context passed to `loadOptions` for async edit configs.
 * Provides row data for per-row option loading.
 * @template T - The row data type
 * @property row - The full row data object
 * @property rowId - The string id of the row
 */
export type AsyncCellContext<T> = {
    row: T;
    rowId: string;
};
/**
 * Eager loader for `mode: "select-async"` — returns all matching options at once.
 * @template T - The row data type
 */
export type SelectAsyncCellEagerLoader<T> = (searchValue: string, context: AsyncCellContext<T>) => SelectMenuOption[] | Promise<SelectMenuOption[]>;
/**
 * Page-based lazy loader for `mode: "select-async"`.
 * @template T - The row data type
 */
export type SelectAsyncCellPageLoader<T> = (searchValue: string, pageNumber: number, pageSize: number, context: AsyncCellContext<T>) => {
    options: SelectMenuOption[];
    hasMore?: boolean;
} | Promise<{
    options: SelectMenuOption[];
    hasMore?: boolean;
}>;
/**
 * Offset-based lazy loader for `mode: "select-async"`.
 * @template T - The row data type
 */
export type SelectAsyncCellOffsetLoader<T> = (searchValue: string, offset: number, limit: number, context: AsyncCellContext<T>) => {
    options: SelectMenuOption[];
    hasMore?: boolean;
} | Promise<{
    options: SelectMenuOption[];
    hasMore?: boolean;
}>;
/**
 * Group-based lazy loader for `mode: "select-async"`.
 * @template T - The row data type
 */
export type SelectAsyncCellGroupLoader<T> = (searchValue: string, previousGroupKey: SelectMenuGroupByValue | null, context: AsyncCellContext<T>) => {
    options: SelectMenuOption[];
    hasMore?: boolean;
} | Promise<{
    options: SelectMenuOption[];
    hasMore?: boolean;
}>;
/**
 * Eager loader for `mode: "multiselect-async"` — returns all matching options at once.
 * @template T - The row data type
 */
export type MultiselectAsyncCellEagerLoader<T> = (searchValue: string, context: AsyncCellContext<T>) => MultiSelectMenuOption[] | Promise<MultiSelectMenuOption[]>;
/**
 * Page-based lazy loader for `mode: "multiselect-async"`.
 * @template T - The row data type
 */
export type MultiselectAsyncCellPageLoader<T> = (searchValue: string, pageNumber: number, pageSize: number, context: AsyncCellContext<T>) => {
    options: MultiSelectMenuOption[];
    hasMore?: boolean;
} | Promise<{
    options: MultiSelectMenuOption[];
    hasMore?: boolean;
}>;
/**
 * Offset-based lazy loader for `mode: "multiselect-async"`.
 * @template T - The row data type
 */
export type MultiselectAsyncCellOffsetLoader<T> = (searchValue: string, offset: number, limit: number, context: AsyncCellContext<T>) => {
    options: MultiSelectMenuOption[];
    hasMore?: boolean;
} | Promise<{
    options: MultiSelectMenuOption[];
    hasMore?: boolean;
}>;
/**
 * Group-based lazy loader for `mode: "multiselect-async"`.
 * @template T - The row data type
 */
export type MultiselectAsyncCellGroupLoader<T> = (searchValue: string, previousGroupKey: SelectMenuGroupByValue | null, context: AsyncCellContext<T>) => {
    options: MultiSelectMenuOption[];
    hasMore?: boolean;
} | Promise<{
    options: MultiSelectMenuOption[];
    hasMore?: boolean;
}>;
type SelectAsyncEditConfigBase = {
    /**
     * Callback fired when the selected option changes.
     * @param option - The newly selected option, or null if cleared
     * @param rowId - The id of the row being edited
     */
    onChange: (option: SelectMenuOption | null, rowId: string) => void;
} & SelectMenuAsyncCellPassthroughProps;
/**
 * Edit configuration for async select mode cells.
 * Uses `SelectMenu` directly (not `SelectMenuSync`) to support server-side option loading.
 *
 * The `loadOptions` function receives a `context` argument as its last parameter,
 * containing the current row data and row id. This enables per-row option loading.
 *
 * By default, caching is disabled to prevent cross-row cache pollution when `loadOptions`
 * uses row context. Pass `cache={{ enabled: true }}` to override.
 *
 * Cell value is expected to be a primitive that matches a `SelectMenuOption.id`.
 *
 * @template T - The row data type
 */
export type SelectAsyncEditConfig<T> = (SelectAsyncEditConfigBase & {
    mode: "select-async";
    lazy?: false;
    loadOptions: SelectAsyncCellEagerLoader<T>;
    lazyOptions?: never;
}) | (SelectAsyncEditConfigBase & {
    mode: "select-async";
    lazy: "page";
    loadOptions: SelectAsyncCellPageLoader<T>;
    lazyOptions?: {
        pageSize?: number;
    };
}) | (SelectAsyncEditConfigBase & {
    mode: "select-async";
    lazy: "offset";
    loadOptions: SelectAsyncCellOffsetLoader<T>;
    lazyOptions?: {
        limit?: number;
    };
}) | (SelectAsyncEditConfigBase & {
    mode: "select-async";
    lazy: "group";
    loadOptions: SelectAsyncCellGroupLoader<T>;
    lazyOptions?: object;
});
type MultiselectAsyncEditConfigBase = {
    /**
     * Callback fired when the selected options change.
     * @param options - The newly selected options (full option objects)
     * @param rowId - The id of the row being edited
     */
    onChange: (options: MultiSelectMenuOption[], rowId: string) => void;
} & MultiSelectMenuAsyncCellPassthroughProps;
/**
 * Edit configuration for async multiselect mode cells.
 * Uses `MultiSelectMenu` directly (not `MultiSelectMenuSync`) to support server-side option loading.
 *
 * The `loadOptions` function receives a `context` argument as its last parameter,
 * containing the current row data and row id. This enables per-row option loading.
 *
 * By default, caching is disabled to prevent cross-row cache pollution when `loadOptions`
 * uses row context. Pass `cache={{ enabled: true }}` to override.
 *
 * **Value contract**: Unlike `mode: "multiselect"` (which stores ID arrays), the cell value
 * for `mode: "multiselect-async"` must be `MultiSelectMenuOption[]` — full option objects.
 * The `onChange` callback receives these objects directly and the consumer stores them wholesale.
 *
 * @template T - The row data type
 */
export type MultiselectAsyncEditConfig<T> = (MultiselectAsyncEditConfigBase & {
    mode: "multiselect-async";
    lazy?: false;
    loadOptions: MultiselectAsyncCellEagerLoader<T>;
    lazyOptions?: never;
}) | (MultiselectAsyncEditConfigBase & {
    mode: "multiselect-async";
    lazy: "page";
    loadOptions: MultiselectAsyncCellPageLoader<T>;
    lazyOptions?: {
        pageSize?: number;
    };
}) | (MultiselectAsyncEditConfigBase & {
    mode: "multiselect-async";
    lazy: "offset";
    loadOptions: MultiselectAsyncCellOffsetLoader<T>;
    lazyOptions?: {
        limit?: number;
    };
}) | (MultiselectAsyncEditConfigBase & {
    mode: "multiselect-async";
    lazy: "group";
    loadOptions: MultiselectAsyncCellGroupLoader<T>;
    lazyOptions?: object;
});
/**
 * Edit configuration for boolean mode cells.
 * Renders a dropdown menu with predefined true/false options and an optional null option.
 *
 * @template T - The row data type
 * @template K - The column key
 */
export type BooleanEditConfig<T, K extends keyof T> = BaseEditConfig<T, K> & {
    /**
     * Boolean edit mode - renders a dropdown with true/false/null options.
     */
    mode: "boolean";
    /**
     * The label displayed for the `true` option.
     * @default "True"
     */
    trueLabel?: string;
    /**
     * The label displayed for the `false` option.
     * @default "False"
     */
    falseLabel?: string;
    /**
     * Whether to include a null option in the dropdown.
     * @default false
     */
    allowNull?: boolean;
    /**
     * The label displayed for the `null` option. Only used when `allowNull` is true.
     * @default "Unset"
     */
    nullLabel?: string;
};
/**
 * Union of all edit configurations.
 * Use with `editConfig` property on column definitions.
 *
 * @template T - The row data type
 * @template K - The column key
 *
 * @example
 * ```ts
 * // Text editing
 * editConfig: { mode: "text", onChange: (value, rowId) => save(value, rowId) }
 *
 * // Number editing
 * editConfig: {
 *   mode: "number",
 *   minValue: 0,
 *   maxValue: 1000,
 *   step: 1,
 *   onChange: (value, rowId) => save(value, rowId)
 * }
 *
 * // Select editing
 * editConfig: {
 *   mode: "select",
 *   options: [{ id: "active", label: "Active" }],
 *   onChange: (option, rowId) => save(option?.id, rowId)
 * }
 *
 * // Boolean editing
 * editConfig: {
 *   mode: "boolean",
 *   trueLabel: "Yes",
 *   falseLabel: "No",
 *   onChange: (value, rowId) => save(value, rowId)
 * }
 * ```
 */
export type EditConfig<T, K extends keyof T> = TextEditConfig<T, K> | NumberEditConfig<T, K> | SelectEditConfig<T, K> | SelectAsyncEditConfig<T> | MultiselectEditConfig<T, K> | MultiselectAsyncEditConfig<T> | BooleanEditConfig<T, K>;
/**
 * The type for a table row
 * @extends T
 */
export type TableRow<T> = T & {
    /**
     * The id of the row
     */
    id: string | number;
    /**
     * Row metadata including errors
     */
    meta?: {
        /**
         * Cell-level errors keyed by column id.
         * - `true` marks the cell as having an error
         * - A string marks the cell as having an error with an accessible error message
         */
        errors?: Partial<Record<keyof T, boolean | string>>;
        /**
         * Cell-level warnings keyed by column id.
         * - `true` marks the cell as having a warning
         * - A string marks the cell as having a warning with an accessible warning message
         * - When both an error and warning exist on the same cell, the error takes priority
         */
        warnings?: Partial<Record<keyof T, boolean | string>>;
        /**
         * Row-level error displayed in the first column.
         * - `true` marks the row as having an error
         * - A string marks the row as having an error with an accessible error message
         */
        rowError?: boolean | string;
        /**
         * Row-level warning displayed in the first column.
         * - `true` marks the row as having a warning
         * - A string marks the row as having a warning with an accessible warning message
         * - When both a row error and warning exist, the error takes priority
         */
        rowWarning?: boolean | string;
    };
    /**
     * The sub component displayed when the row is expanded
     */
    subComponent?: ReactNode;
    /**
     * The sub rows of the row when the row is expanded
     */
    subRows?: TableRow<T>[];
};
/**
 * Column definition type for DataTable columns.
 *
 * Use `createColumnHelper<T>()` to create type-safe column definitions with
 * proper type inference for `type`, `editConfig`, and value types.
 *
 * @example
 * ```ts
 * type Data = { name: string; amount: number; tags: string[] };
 * const createColumn = createColumnHelper<Data>();
 *
 * const columns = [
 *   // Display-only column with type defaults
 *   createColumn("amount", { header: { label: "Amount" }, type: "currency" }),
 *
 *   // Editable column with editConfig
 *   createColumn("name", {
 *     header: { label: "Name" },
 *     type: "text",
 *     editConfig: { mode: "text", onChange: (value, rowId) => save(value, rowId) }
 *   }),
 *
 *   // Multiselect editing
 *   createColumn("tags", {
 *     header: { label: "Tags" },
 *     editConfig: {
 *       mode: "multiselect",
 *       options: [{ value: "urgent", label: "Urgent" }],
 *       onChange: (value, rowId) => save(value, rowId)
 *     }
 *   }),
 * ];
 * ```
 */
export type ColumnHeader = {
    /**
     * The visible header label text.
     */
    label: string;
    /**
     * Whether the header should show a required indicator.
     */
    required?: boolean;
    /**
     * Additional contextual content rendered from a keyboard-accessible more-info trigger.
     */
    moreInfo?: ReactNode;
};
export type ColumnHeaderConfig = {
    /**
     * The forward-looking header configuration.
     */
    header: ColumnHeader;
    /**
     * Legacy header label support during the transition to `header`.
     * @deprecated Use `header.label` instead.
     */
    headerLabel?: string;
} | {
    /**
     * The forward-looking header configuration.
     */
    header?: ColumnHeader;
    /**
     * Legacy header label support during the transition to `header`.
     * @deprecated Use `header.label` instead.
     */
    headerLabel: string;
};
export type ColumnDef<T> = ColumnHeaderConfig & {
    /**
     * The id of the column - must be a key of T
     */
    id: keyof T;
    /**
     * The alignment of the header and cell content.
     * When using `type`, this is set automatically but can be overridden.
     */
    align?: "start" | "center" | "end";
    /**
     * Columns of a group column
     */
    columns?: ColumnDef<T>[];
    /**
     * Configuration for cell editing. Presence enables editing for the column.
     * Consolidates edit mode, options, and onChange into a single object.
     *
     * @example
     * ```ts
     * // Text editing
     * editConfig: { mode: "text", onChange: (value, rowId) => save(value, rowId) }
     *
     * // Select editing
     * editConfig: {
     *   mode: "select",
     *   options: [{ id: "active", label: "Active" }],
     *   onChange: (option, rowId) => save(option?.id, rowId)
     * }
     * ```
     */
    editConfig?: EditConfig<T, keyof T>;
    /**
     * Custom content to display when a cell value is empty (null, undefined, or empty string).
     * Overrides the default em dash. When set on both the column and the DataTable,
     * the column-level value takes precedence.
     */
    emptyCellContent?: ReactNode;
    /**
     * The content of the footer cell. An array will display multiple footer rows
     */
    footerContent?: ReactNode | ReactNode[];
    /**
     * The maximum width of the column, in pixels. Caps automatic growth when
     * the table has extra horizontal space available.
     */
    maxWidth?: number;
    /**
     * The minimum width of the column, in pixels. Used as the floor for manual
     * resize — users can drag a column down to but not below this value. Also
     * serves as the fallback auto-sizing floor when `defaultWidth` is not set.
     */
    minWidth?: number;
    /**
     * The preferred starting width of the column, in pixels. Used as the basis
     * for automatic growing/shrinking: the column renders at this width by
     * default, grows toward `maxWidth` when the table has spare horizontal
     * space, and never auto-shrinks below it — the table scrolls horizontally
     * instead.
     *
     * Manual resize via the column's resize handle is still bounded by
     * `minWidth`/`maxWidth`, so users can drag a column below `defaultWidth`
     * down to `minWidth`.
     *
     * Falls back to `minWidth` when not specified.
     *
     * @remarks Provide a value between `minWidth` and `maxWidth` (inclusive).
     * Values outside that envelope are not validated; CSS grid will clamp at
     * render time.
     */
    defaultWidth?: number;
    /**
     * The pinning location of the column
     */
    pinned?: "left" | "right";
    /**
     * The function to customize how the cell content is rendered.
     * When using `type`, a default renderer is provided but can be overridden.
     */
    renderCell?: (value: T[keyof T], { row, depth }: {
        row?: T;
        depth?: number;
    }) => ReactNode;
    /**
     * Whether the column is resizable
     */
    resizable?: boolean;
    /**
     * Whether the column is sortable, or a function to customize the sorting logic.
     * When a function, receives values of the column's value type.
     */
    sortable?: boolean | ((valueA: T[keyof T], valueB: T[keyof T]) => number);
    /**
     * The column type for automatic display configuration.
     * Sets default `renderCell` (formatter) and `align` based on the data type.
     *
     * @example
     * ```ts
     * // Simple - uses default formatter options
     * type: "currency"
     *
     * // With options - customizes formatter behavior
     * type: { type: "currency", options: { currency: "EUR", locale: "de-DE" } }
     * ```
     */
    type?: ColumnTypeConfig;
};
/**
 * The type for a custom table footer cell props
 */
export type CustomTableFooterCellProps = {
    /**
     * The content of the footer cell
     */
    content: ReactNode;
    /**
     * The number of columns the footer cell should span
     */
    colSpan: number;
};
export {};
