import { ComputedQuery, FiltersMap, ToastConfig } from '@wix/bex-core';

import React, {
  JSXElementConstructor,
  ReactElement,
  ReactNode,
  Ref,
} from 'react';
import { CollectionDragAndDropParentState } from './CollectionDragAndDropState';

export interface IndexedItem<T> {
  id: string;
  item: T;
  index: number;
}

export interface CollectionDragEndEvent<T, F extends FiltersMap> {
  from: IndexedItem<T>;
  after: IndexedItem<T> | null;
  over: IndexedItem<T>;
  filters: ComputedQuery<F>['filters'];
}

export type DragAndDropSubmit<T, F extends FiltersMap> = (
  event: CollectionDragEndEvent<T, F>,
) => Promise<unknown>;

export type DragAndDropCancelResult =
  | Omit<ToastConfig, 'type' | 'biName'>
  | boolean
  | null
  | undefined
  | void;

export type DragAndDropCancel<T, F extends FiltersMap> = (
  event: CollectionDragEndEvent<T, F>,
) => DragAndDropCancelResult | Promise<DragAndDropCancelResult>;

export type DragAndDropBulkSubmit<T, F extends FiltersMap> = (
  events: CollectionDragEndEvent<T, F>[],
  snapshot: T[][],
) => Promise<unknown>;

// Context
export interface SortableContextProps<T, F extends FiltersMap> {
  state: CollectionDragAndDropParentState<T, F>;
  children?: ReactNode;
  onSubmit?: DragAndDropSubmit<T, F>;
  onCancel?: DragAndDropCancel<T, F>;
}

// Draggable
export interface GridCardItemProps {
  index: number;
  rowIndex?: number;
  columnIndex?: number;
  droppable?: boolean;
  draggable?: boolean;
  dragging?: boolean;
  dragHandleProps?: React.HTMLAttributes<HTMLDivElement> & {
    domRef?: Ref<HTMLDivElement>;
  };
  domRef?: (node: HTMLDivElement | null) => void;
}

type GridCardItem = React.ReactElement<
  GridCardItemProps,
  JSXElementConstructor<GridCardItemProps>
>;

export interface DraggableCardProps<T, F extends FiltersMap> {
  state: CollectionDragAndDropParentState<T, F>;
  index: number;
  id: string;
  isOverlay?: boolean;
  dndDisabled?: boolean;
  children: GridCardItem;
}

// Overlay

export interface DraggableCardOverlayProps<T, F extends FiltersMap> {
  state: CollectionDragAndDropParentState<T, F>;
  renderItem: (index: number) => ReactElement | null;
}

export interface DragAndDrop {
  SortableContext: <T, F extends FiltersMap>(
    props: SortableContextProps<T, F>,
  ) => JSX.Element;
  DraggableCard: <T, F extends FiltersMap>(
    props: DraggableCardProps<T, F>,
  ) => JSX.Element;
  DraggableCardOverlay: <T, F extends FiltersMap>(
    props: DraggableCardOverlayProps<T, F>,
  ) => JSX.Element;
}
