import { ReactNode } from 'react';

/**
 * Defines the structure of a table column
 * @template T - Type of data being displayed in the table
 */
interface Column<T> {
    /** Unique identifier for the column */
    id: keyof T;
    /** Header content or function to render header */
    header: ReactNode | (() => ReactNode);
    /** Key to access data in row object */
    accessorKey: keyof T;
    /** Whether the column is sortable */
    sortable?: boolean;
    /** Additional CSS classes for the column */
    className?: string;
    /** Width of the column */
    width?: string;
    /** Group name for the column */
    group?: string;
    /** Pin position for the column */
    pinned?: 'left' | 'right' | false;
    /** Custom cell renderer */
    cell?: (props: {
        value: T[keyof T];
        row: T;
        onChange?: (value: T[keyof T]) => void;
        onDelete?: () => void;
        table?: {
            options: {
                meta: {
                    updateData: UpdateDataFn<T>;
                };
            };
        };
    }) => ReactNode;
}
interface HeaderGroup<T> {
    id: string;
    name: string;
    columns: Column<T>[];
}
/**
 * Configuration for column resizing functionality
 */
interface ColumnResizeInfoState {
    /** Starting X coordinate of resize operation */
    startX: number | null;
    /** Current X coordinate during resize */
    currentX: number | null;
    /** Change in X coordinate from start */
    deltaX: number | null;
    /** ID of column being resized or false if none */
    isResizingColumn: string | false;
    /** Initial widths of columns when resize started */
    columnSizingStart: {
        [key: string]: number;
    };
}
type ColumnResizeMode = 'onChange' | 'onResize';

/**
 * Type definitions for table events
 */
interface TableEventMap<T> {
    /** Called when a column is sorted */
    onSort: (column: Column<T>, direction: SortDirection) => void;
    /** Called when the filter value changes */
    onFilter: (value: string, filteredData: T[]) => void;
    /** Called when a column is resized */
    onColumnResize: (columnId: keyof T, width: number) => void;
    /** Called when a column's visibility changes */
    onColumnVisibilityChange: (columnId: keyof T, isVisible: boolean) => void;
    /** Called when a column is pinned/unpinned */
    onColumnPin: (columnId: keyof T, position: 'left' | 'right' | false) => void;
    /** Called when a row is selected */
    onRowSelect: (row: T, index: number) => void;
    /** Called when the table state changes */
    onStateChange: (state: TableState<T>) => void;
}
/**
 * Configuration for server-side operations
 */
interface ServerSideConfig<T> {
    enabled: boolean;
    totalRows: number;
    pageSize: number;
    currentPage: number;
    loading: boolean;
    onFetch: (options: {
        page: number;
        pageSize: number;
        sortColumn?: keyof T;
        sortDirection?: SortDirection;
        filters?: Record<string, unknown>;
    }) => Promise<T[]>;
    onPageChange?: (page: number) => void;
}
/**
 * Configuration for virtualization
 */
interface VirtualizationConfig {
    enabled: boolean;
    rowHeight: number;
    overscan: number;
    scrollingDelay?: number;
    initialScrollOffset?: number;
    onEndReached?: () => void;
}

type TableVariant = "modern" | "minimal" | "classic";
type SortDirection = "asc" | "desc";
type UpdateDataFn<T> = (index: number, field: keyof T, value: T[keyof T]) => void;
interface TableState<T> {
    data: T[];
    sortColumn: keyof T;
    sortDirection: SortDirection;
    filterValue?: string;
    visibleColumns: Array<keyof T>;
    pinnedColumns: {
        left: Array<keyof T>;
        right: Array<keyof T>;
    };
    columnSizing: {
        columnSizes: {
            [key: string]: number;
        };
    };
    columnResizeMode: ColumnResizeMode;
    loading?: boolean;
}
interface TableCustomComponents<T> {
    Header?: React.ComponentType<{
        column: Column<T>;
        sortIcon?: React.ReactNode;
        onSort?: () => void;
    }>;
    Cell?: React.ComponentType<{
        column: Column<T>;
        row: T;
        value: T[keyof T];
    }>;
    EmptyState?: React.ComponentType;
    LoadingState?: React.ComponentType;
    SearchInput?: React.ComponentType<{
        value: string;
        onChange: (value: string) => void;
        placeholder?: string;
    }>;
    renderCell?: (row: T, rowIndex: number, value: unknown) => React.ReactNode;
    renderLoading?: () => React.ReactNode;
    renderEmpty?: () => React.ReactNode;
    renderError?: (error: Error) => React.ReactNode;
}
interface TableStyleConfig {
    container?: {
        className?: string;
        style?: React.CSSProperties;
        wrapperClassName?: string;
        scrollContainerClassName?: string;
        tableClassName?: string;
    };
    header?: {
        className?: string;
        style?: React.CSSProperties;
        headerRowClassName?: string;
        TableColumnClassName?: string;
        headerGroupClassName?: string;
    };
    body?: {
        style?: React.CSSProperties;
        className?: string;
        rowClassName?: string;
        cellClassName?: string;
    };
    resizer?: {
        className?: string;
        style?: React.CSSProperties;
    };
    resizerIndicator?: {
        className?: string;
        style?: React.CSSProperties;
    };
    sortButton?: {
        className?: string;
        style?: React.CSSProperties;
    };
    utilityStyles?: {
        emptyClassName?: string;
        searchContainerClassName?: string;
        searchInputClassName?: string;
        loadingClassName?: string;
        style?: React.CSSProperties;
    };
}
type FuseKeys<T> = Array<keyof T | string>;
interface TableCustomRender<T> {
    renderHeader?: (column: Column<T>) => ReactNode;
    renderCell?: (row: T, rowIndex: number, value: T[keyof T]) => ReactNode;
    renderEmpty?: () => ReactNode;
    renderLoading?: () => ReactNode;
    renderSearch?: (props: {
        value: string;
        onChange: (value: string) => void;
        placeholder?: string;
    }) => ReactNode;
}
interface TableProps<T> {
    columns: Column<T>[];
    data: T[];
    variant?: TableVariant;
    className?: string;
    sortColumn?: keyof T;
    sortDirection?: SortDirection;
    gridTemplateColumns?: string;
    maxHeight?: string;
    onRowChange?: UpdateDataFn<T>;
    onRowDelete?: (index: number) => void;
    meta?: {
        updateData?: UpdateDataFn<T>;
    };
    filterValue?: string;
    onFilterChange?: (value: string) => void;
    filterPlaceholder?: string;
    enableFiltering?: boolean;
    headerGroups?: boolean;
    enableFuzzySearch?: boolean;
    fuzzySearchKeys?: FuseKeys<T>;
    fuzzySearchThreshold?: number;
    /** Whether column resizing is enabled. Defaults to false. */
    enableColumnResize?: boolean;
    components?: TableCustomComponents<T>;
    styleConfig?: TableStyleConfig;
    renderHeader?: (column: Column<T>) => ReactNode;
    renderCell?: (column: Column<T>, row: T, value: T[keyof T]) => ReactNode;
    renderEmpty?: () => ReactNode;
    renderLoading?: () => ReactNode;
    renderSearch?: (props: {
        value: string;
        onChange: (value: string) => void;
        placeholder?: string;
    }) => ReactNode;
    isLoading?: boolean;
    columnResizeMode?: ColumnResizeMode;
    onColumnSizingChange?: (columnSizing: {
        columnSizes: {
            [key: string]: number;
        };
    }) => void;
    columnResizeDirection?: "ltr" | "rtl";
    columnResizeInfo?: ColumnResizeInfoState;
    columnSizing?: {
        columnSizes: {
            [key: string]: number;
        };
    };
    virtualization?: VirtualizationConfig;
    serverSide?: ServerSideConfig<T>;
    events?: Partial<TableEventMap<T>>;
}
interface TableGridReturn<T> {
    data: T[];
    setData: (data: T[]) => void;
    sortColumn: keyof T;
    sortDirection: SortDirection;
    handleSort: (column: Column<T>) => void;
    filterValue: string;
    setFilterValue: (value: string) => void;
    filteredData: T[];
    state: TableState<T>;
    resetState: () => void;
    visibleColumns: Array<keyof T>;
    toggleColumnVisibility: (columnId: keyof T) => void;
    pinnedColumns: {
        left: Array<keyof T>;
        right: Array<keyof T>;
    };
    toggleColumnPin: (columnId: keyof T, position: "left" | "right" | false) => void;
}
interface TableContextValue<T> {
    state: TableState<T>;
    columns: Column<T>[];
    data: T[];
    filteredData: T[];
    visibleColumns: Array<keyof T>;
    toggleColumnVisibility: (columnId: keyof T) => void;
    pinnedColumns: {
        left: Array<keyof T>;
        right: Array<keyof T>;
    };
    toggleColumnPin: (columnId: keyof T, position: "left" | "right" | false) => void;
    sortColumn: keyof T;
    sortDirection: SortDirection;
    handleSort: (column: Column<T>) => void;
    filterValue: string;
    setFilterValue: (value: string) => void;
    columnSizing: {
        columnSizes: {
            [key: string]: number;
        };
    };
    columnResizeInfo: ColumnResizeInfoState;
    columnResizeMode: "onChange" | "onResize";
    columnResizeDirection: "ltr" | "rtl";
    handleColumnResize: (columnId: string, width: number) => void;
    handleColumnResizeStart: (columnId: string, startX: number) => void;
    handleColumnResizeMove: (currentX: number) => void;
    handleColumnResizeEnd: () => void;
    handleRowSelect: (row: T, index: number) => void;
    resetState: () => void;
    setData: (data: T[]) => void;
    handleStateChange: (state: TableState<T>) => void;
}

export type { Column, ColumnResizeInfoState, ColumnResizeMode, HeaderGroup, ServerSideConfig, SortDirection, TableContextValue, TableCustomComponents, TableCustomRender, TableEventMap, TableGridReturn, TableProps, TableState, TableStyleConfig, TableVariant, UpdateDataFn, VirtualizationConfig };
