import * as React from 'react';
import {
  DataTableColumn,
  DataTableProps,
  DataTableResizeProps,
  RowDataDefaultType,
  DragStartEvent,
  DragEndEvent,
} from './DataTable';
import EmptyState from '../EmptyState';

export interface TableProps<
  RowData = RowDataDefaultType,
> extends UsedDataTableProps<RowData> {
  /** Applies a data-hook HTML attribute to be used in the tests */
  dataHook?: string;
  /** Defines a callback function which is called when selection happens. <br />
   * There are 3 types of selections:
   *    * `ALL` - bulk selection checkbox has been triggered to select all items
   *    * `SINGLE_TOGGLE` - a checkbox to select one item from the list has been triggered. The change object will also include an `id` prop with the unique item identifier and a `value` prop with the new boolean selection state of the item.
   *    * `NONE` - bulk selection has been triggered to unselect all items.
   *  */
  onSelectionChanged?: OnSelectionChangedFn;
  /** Called when item selection triggered but not changed yet. */
  onSelectionStarted?(): void;
  /** Displays selection checkbox as a first column in each row. To hide the selection checkbox from a specific row, set its `row.unselectable` value to true in the data array.
   * @default false
   */
  showSelection?: boolean;
  /** When true and showSelection is enabled, displays row numbers in the selection column.
   * The checkbox appears on hover or when the row is selected.
   * @default false
   */
  showRowNumbers?: boolean;
  /** Hides bulk selection checkbox in the table titlebar
   * @default false
   */
  hideBulkSelectionCheckbox?: boolean;
  /** A ref to the bulk selection checkbox in the table titlebar */
  bulkSelectionCheckboxRef?: React.Ref<HTMLInputElement>;
  /** Defines an array of selected rows */
  selectedIds?: string[] | number[];
  /** Specifies whether table row selection is restricted at a given moment. Can be defined as:
   *    * `bool` disables selection for all table rows
   *    * `function` that will be called for each row to check whether to disable selection or not depending on specified condition */
  selectionDisabled?: boolean | SelectionDisabledFn<RowData>;
  /** Controls bulk selection checkbox behaviour in indeterminate state. By default, first click on indeterminate state selects all items in the table. If set to `true`, first click will deselect all items instead.
   * @default false
   */
  deselectRowsByDefault?: boolean;
  /**
   *  When false then Table would not create a `<div/>` wrapper around it's children.
   *  Useful when using `<Table/>` to wrap a `<Page/>` component, in that case we use the `<Table/>` only as a context provider and it does not render anything to the DOM by itself.
   * @default true
   */
  withWrapper?: boolean;
  controlled?: boolean;
  viewportRef?: React.RefObject<HTMLElement | null | undefined>;
  /**
   * Defines a callback function which is called on column title click
   */
  onSortClick?(colData: TableColumn, colNum: number): void;
  /** Specifies the total number of selectable items in the table (including items not loaded yet).
   * When ‘Select all’ is triggered in infinite scroll tables, newly loaded items will be selected automatically. In this case, `SelectionContext` holds not-selected items rather than the selected ones.
   * SelectionContext.infiniteBulkSelected is true and SelectionContext.selectedCount is the value of totalSelectableCount minus the count of unselected items. */
  totalSelectableCount?: number;
  /** Configures table columns. Required properties for each column:<br />
   *    * `title`: specifies a text string or an element to display in the table titlebar
   *    * `render`: defines a function which will be called to display this row value for this column<br>
   *
   *  Optional properties for each column:
   *    * `onCellClick`: defines a  callback function which is called each time a cell in this column is clicked. Signature: `onCellClick(column, rowData, rowNum, event)`
   *    * `sortable`: specifies whether field is sortable. If true clicking the header will call `onSortClick`.
   *    * `sortDescending`: specifies what sort icon to display in the column header. `true` shows an up arrow, `false` shows a down arrow, `undefined' shows no icon.
   *    * `infoTooltipProps`: controls info [tooltip](/?path=/story/components-overlays--tooltip) appearance in titlebar. Note: `dataHook`, `moveBy` and `children` will not be passed to tooltip.
   *    * `style`: applies a custom CSS class to the component’s root element
   *    * `align`: controls the alignment of the column content
   *    * `width`: sets the width of a column. No value means column will try to contain its children, if possible.
   *    * `important`: increases text size of this column data across all rows, sets font color to D10
   *    * `stickyActionCell`: specifies whether `<TableActionCell/>` controls are fixed to the right side of the table
   *    * `resizeProps`: configures column resize behavior. When provided with an `id`, enables resizing for this column. Use `disabled: true` to show a disabled handle, or `disabled: true, hideDisabledResizeHandle: true` to hide the handle completely.
   *    */
  columns: TableColumn<RowData>[];
  dragAndDrop?: any;
  onDragEnd?(event: DragEndEvent): unknown;
  onDragStart?(event: DragStartEvent): unknown;
  onDragCancel?(event: DragEndEvent): unknown;
  isDragAndDropDisabled?: boolean;
  /** Accept any wrapper component as a child element. It must eventually include <Table.Content/>. */
  children?: React.ReactNode;
}

export interface SelectionContext {
  isSelected(id: string): boolean;
  selectedCount: number;
  getSelectedIds(): string[];
  getNotSelectedIds(): string[];
  infiniteBulkSelected: boolean;
  bulkSelectionState: 'ALL' | 'NONE' | 'SOME';
  toggleSelectionById(): void;
  /** Controls bulk selection checkbox behaviour in indeterminate state. By default, first click on indeterminate state selects all items in the table. If set to `true`, first click will deselect all items instead.
   * @default false
   */
  deselectRowsByDefault: boolean;
  toggleAll(deselectRowsByDefault?: boolean): void;
  selectAll(): void;
  deselectAll(): void;
  setSelectedIds(ids: string[]): void;
  /** Specifies whether table row selection is restricted at a given moment. Can be defined as:
   *    * `bool` disables selection for all table rows
   *    * `function` that will be called for each row to check whether to disable selection or not depending on specified condition */
  selectionDisabled: boolean | (() => boolean);
}

declare const ToolbarContainer: React.FC<{
  /** Accept any wrapper component as a child element. It must eventually include <Table.Content/>. */
  children: (selectionContext: SelectionContext) => React.ReactNode;
}>;
declare const SubToolbar: React.FunctionComponent<
  React.PropsWithChildren<{ dataHook?: string }>
>;
declare const Titlebar: React.FC<{ dataHook?: string }>;
declare const Content: React.FC<{
  titleBarVisible?: boolean;
  titleBarDisplay?: boolean;
  /** Applies a data-hook HTML attribute to be used in the tests */
  dataHook?: string;
}>;
declare const BulkSelectionCheckbox: React.FC<
  React.PropsWithChildren<{ dataHook: string }>
>;

export type TableColumn<RowDataType = RowDataDefaultType> =
  DataTableColumn<RowDataType>;

export type OnSelectionChangedFn = (
  /** Defines an array of selected rows */
  selectedIds: TableProps['selectedIds'] | null,
  change:
    | {
        type: 'SINGLE_TOGGLE';
        /** Assigns an unique identifier for the table */
        id: string;
        value: boolean;
        origin: string;
      }
    | {
        type: 'ALL' | 'NONE';
        origin: string;
      },
) => void;

export type SelectionDisabledFn<RowData = RowDataDefaultType> = (
  rowData: RowData,
) => void;

export type UsedDataTableProps<RowData = RowDataDefaultType> = Pick<
  DataTableProps<RowData>,
  | 'allowMultiDetailsExpansion'
  | 'dynamicRowClass'
  | 'isRowHighlight'
  | 'isRowActive'
  | 'hasMore'
  | 'initialLoad'
  | 'id'
  | 'infiniteScroll'
  | 'itemsPerPage'
  | 'loader'
  | 'loadMore'
  | 'onRowClick'
  | 'onMouseEnterRow'
  | 'onMouseLeaveRow'
  | 'useWindow'
  | 'scrollElement'
  | 'rowVerticalPadding'
  | 'rowDetails'
  | 'removeRowDetailsPadding'
  | 'rowDataHook'
  | 'rowClass'
  | 'headerRowClass'
  | 'headerClass'
  | 'showHeaderWhenEmpty'
  | 'showLastRowDivider'
  | 'virtualized'
  | 'virtualizedTableHeight'
  | 'virtualizedLineHeight'
  | 'virtualizedListRef'
  | 'width'
  | 'skin'
  | 'data'
  | 'horizontalScroll'
  | 'stickyColumns'
  | 'isRowDisabled'
  | 'infiniteScrollRef'
  | 'isApplyColumnWidthStyle'
  | 'resizable'
  | 'resizeProps'
>;

export default class Table<
  RowData = RowDataDefaultType,
> extends React.Component<TableProps<RowData>> {
  static ToolbarContainer: typeof ToolbarContainer;
  static Titlebar: typeof Titlebar;
  static SubToolbar: typeof SubToolbar;
  static Content: typeof Content;
  static EmptyState: typeof EmptyState;
  static BulkSelectionCheckbox: typeof BulkSelectionCheckbox;
  static dataTableRowVirtualStyle?: import('@stylable/runtime').RuntimeStylesheet;
  static dataTableRowStyle: import('@stylable/runtime').RuntimeStylesheet;

  setSelectedIds: (selectedIds: TableProps['selectedIds']) => void;
}
