import { ReactNode, ComponentProps } from 'react';
import { Link } from '@mui/joy';
import { Table } from '../Table';
import CurrencyInput from '../CurrencyInput';
import DatePicker from '../DatePicker';
import Input from '../Input';
import Textarea from '../Textarea';
import Autocomplete from '../Autocomplete';
import Select from '../Select';
export type ObjectLike<V = any> = Record<PropertyKey, V> | {
    [key: PropertyKey]: V;
};
type ReturnTypeOrNever<T> = T extends (...args: any[]) => infer R ? R : never;
type IdPropType<T> = T extends {
    id: infer ID;
} ? ID : never;
export type InferredIdType<T, GetId> = GetId extends (row: T) => any ? ReturnTypeOrNever<GetId> : IdPropType<T>;
type Handler<T extends ObjectLike, ID, V = any, R = any> = (params: V extends never ? {
    row: T;
    value?: V;
    id: ID;
} : {
    row: T;
    value: V;
    id: ID;
}) => R;
type EventHandler<T extends ObjectLike, ID, V = any> = (params: {
    originalRow: T;
    row: T;
    value?: V;
    id: ID;
}) => void;
type ComponentProperties<C extends React.ElementType, T extends ObjectLike, ID, V = any> = ComponentProps<C> | Handler<T, ID, V, ComponentProps<C>>;
export type RenderCellHandler<T extends ObjectLike, ID, V = any> = Handler<T, ID, V, ReactNode>;
export type CellEditableHandler<T extends ObjectLike, ID, V = any> = Handler<T, ID, V, boolean>;
export type CellEditStartEvent<T extends ObjectLike, ID, V = any> = EventHandler<T, ID, V>;
export type CellEditStopEvent<T extends ObjectLike, ID, V = any> = EventHandler<T, ID, V>;
export type PinnedColumns = {
    left?: string[];
    right?: string[];
};
export type TableColumnHeaderClassNamePropType<R, V> = ((params: {
    field: string;
}) => string | undefined) | string;
export type TableCellClassNamePropType<R, V> = ((params: {
    row: R;
    value: V;
    field: string;
    id: string;
}) => string | undefined) | string;
export type ColumnGroupingModel<T extends Record<PropertyKey, any>, ID = unknown> = {
    groupId: string;
    headerName?: string;
    headerClassName?: string | ((params: {
        groupId: string;
    }) => string);
    children: ColumnGroupingModel<T, ID> | ColumnDef<T, ID>[];
}[];
export type ProcessedColumnGroup = {
    groupId: string;
    headerName?: string;
    headerClassName?: string | ((params: {
        groupId: string;
    }) => string);
    colspan: number;
    level: number;
    startIndex: number;
};
export type FlattenedColumn<T extends Record<PropertyKey, any>, ID> = ColumnDef<T, ID> & {
    groupPath: string[];
    columnIndex: number;
};
export type BaseColumnDef<T extends Record<PropertyKey, V>, V, ID> = {
    [K in keyof T]: {
        field: K;
        headerName?: string;
        headerRef?: React.RefObject<HTMLTableCellElement>;
        tableColRef?: React.RefObject<HTMLTableColElement>;
        width?: string;
        minWidth?: string;
        maxWidth?: string;
        resizable?: boolean;
        renderCell?: RenderCellHandler<T, ID, T[K]>;
        renderEditCell?: RenderCellHandler<T, ID, T[K]>;
        isCellEditable?: CellEditableHandler<T, ID, V> | boolean;
        required?: boolean;
        onCellEditStart?: CellEditStartEvent<T, ID, V>;
        onCellEditStop?: CellEditStopEvent<T, ID, V>;
        sortable?: boolean;
        sortComparator?: (params: {
            rowA: T;
            rowB: T;
        }) => number;
        sortOrder?: Sort[];
        isPinned?: boolean;
        isLastStartPinnedColumn?: boolean;
        isLastEndPinnedColumn?: boolean;
        pinnedStartPosition?: number;
        pinnedEndPosition?: number;
        /**
         * Tooltip 으로 노출되는 설명
         */
        description?: string;
        cellClassName?: TableCellClassNamePropType<T, T[K]>;
        headerClassName?: TableColumnHeaderClassNamePropType<T, T[K]>;
    };
}[keyof T];
export type AutocompleteColumnDef<T extends Record<PropertyKey, string>, ID> = BaseColumnDef<T, string, ID> & {
    type: 'autocomplete';
    componentProps?: ComponentProperties<typeof Autocomplete, T, InferredIdType<T, ID>, string>;
};
export type CurrencyColumnDef<T extends Record<PropertyKey, number>, ID> = BaseColumnDef<T, number, ID> & {
    type: 'currency';
    componentProps?: ComponentProperties<typeof CurrencyInput, T, ID, number>;
};
export type DateColumnDef<T extends Record<PropertyKey, string>, ID> = BaseColumnDef<T, string, ID> & {
    type: 'date';
    componentProps?: ComponentProperties<typeof DatePicker, T, ID, string>;
};
export type NumberColumnDef<T extends Record<PropertyKey, number>, ID> = BaseColumnDef<T, number, ID> & {
    type: 'number';
    componentProps?: ComponentProperties<typeof Input, T, ID, number>;
};
export type TextColumnDef<T extends Record<PropertyKey, string>, ID> = BaseColumnDef<T, string, ID> & {
    type?: 'text';
    componentProps?: ComponentProperties<typeof Input, T, ID, string>;
};
export type LongTextColumnDef<T extends Record<PropertyKey, string>, ID> = BaseColumnDef<T, string, ID> & {
    type: 'longText';
    componentProps?: ComponentProperties<typeof Textarea, T, ID, string>;
};
export type SelectColumnDef<T extends Record<PropertyKey, string>, ID> = BaseColumnDef<T, string, ID> & {
    type: 'select';
    componentProps?: ComponentProperties<typeof Select<string, false>, T, ID, string>;
};
export type LinkColumnDef<T extends Record<PropertyKey, string>, ID, C extends React.ElementType = typeof Link> = BaseColumnDef<T, string, ID> & {
    type: 'link';
    component?: C;
    componentProps?: ComponentProperties<C, T, ID, string>;
};
export type ActionsColumnDef<T extends Record<PropertyKey, string>, ID> = BaseColumnDef<T, string, ID> & {
    type: 'actions';
    getActions: (params: {
        row: T;
        value?: any;
        id: ID;
    }) => ReactNode[];
};
export type ColumnDef<T extends Record<PropertyKey, any>, ID = unknown> = AutocompleteColumnDef<T, ID> | CurrencyColumnDef<T, ID> | DateColumnDef<T, ID> | NumberColumnDef<T, ID> | TextColumnDef<T, ID> | LongTextColumnDef<T, ID> | LinkColumnDef<T, ID> | SelectColumnDef<T, ID> | ActionsColumnDef<T, ID>;
export type Sort = 'asc' | 'desc' | null;
export type SortModel<T extends Record<PropertyKey, any>> = {
    [K in keyof T]: {
        field: K;
        sort: Sort;
    };
}[keyof T];
export interface DataTableApi {
    getRowIndexRelativeToVisibleRows(rowId: string): number;
    setCellFocus(rowId: string): void;
}
export type DataTableProps<T extends Record<PropertyKey, any>, GetId extends ((row: T) => any) | undefined> = {
    rows: T[];
    checkboxSelection?: boolean;
    columns: ColumnDef<T, InferredIdType<T, GetId>>[];
    pinnedColumns?: PinnedColumns;
    columnGroupingModel?: ColumnGroupingModel<T, InferredIdType<T, GetId>>;
    editMode?: boolean;
    /**
     * 체크박스가 있는 경우, 체크박스를 클릭했을 때 선택된 row의 index를 지정한다.
     */
    selectionModel?: InferredIdType<T, GetId>[];
    onSelectionModelChange?: (newSelectionModel: InferredIdType<T, GetId>[], 
    /**
     * Total Select를 클릭한 경우에만 값이 true/false로 들어온다.
     * MUI에는 없는 인터페이스지만 Total Select 기능이 추가되었기 때문에 추가해야했다.
     */
    isTotalSelected?: boolean) => void;
    /**
     * row별로 선택 가능 여부를 결정하는 함수
     */
    isRowSelectable?: (params: {
        row: T;
        id: InferredIdType<T, GetId>;
    }) => boolean;
    disableSelectionOnClick?: boolean;
    initialState?: Partial<{
        sorting: Partial<{
            sortModel: SortModel<T>[];
        }>;
    }>;
    pagination?: boolean;
    paginationMode?: 'client' | 'server';
    paginationModel?: {
        page: number;
        pageSize: number;
    };
    onPaginationModelChange?: (model: {
        page: number;
        pageSize: number;
    }) => void;
    /**
     * 여기서부터 Sort관련 props
     */
    sortModel?: SortModel<T>[];
    sortOrder?: Sort[];
    onSortModelChange?: (model: SortModel<T>[]) => void;
    /**
     * Rows의 총 갯수를 직접 지정 할 수 있다.
     * 기본적으로는 rows.length를 사용하지만, 이 값을 지정하면 rows.length를 사용하지 않는다.
     * server mode를 사용할 때 유용하다.
     */
    rowCount?: number;
    loading?: boolean;
    getId?: GetId;
    onRowClick?: (params: {
        row: T;
        rowId: InferredIdType<T, GetId>;
    }, event: React.MouseEvent) => void;
    /**
     * 기본적으로 Uncontrolled로 작동하지만, Controlled로 작동하게 하고 싶을 때 사용한다.
     * 이 값이 true이면, 현재 페이지 이외에도 존재하는 모든 데이터가 선택된것으로 간주하고 동작한다.
     */
    isTotalSelected?: boolean;
    slots?: {
        checkbox?: React.ElementType;
        toolbar?: React.ElementType;
        footer?: React.ElementType;
        loadingOverlay?: React.ElementType;
    };
    slotProps?: {
        checkbox?: Partial<{
            checked: boolean;
            [key: string]: any;
        }>;
        toolbar?: Partial<{
            [key: string]: any;
        }>;
        background?: Partial<{
            [key: string]: any;
        }>;
    };
} & ComponentProps<typeof Table>;
export {};
