import React, { ReactNode, useEffect, useState } from 'react';
import {
  AutoScrollActivator,
  closestCenter,
  DndContext,
  KeyboardSensor,
  PointerSensor,
  useSensor,
  useSensors,
} from '@wix/wix-style-react-incubator/dnd-kit/core';
import {
  rectSortingStrategy,
  SortableContext,
} from '@wix/wix-style-react-incubator/dnd-kit/sortable';
import { restrictToWindowEdges } from '@wix/wix-style-react-incubator/dnd-kit/modifiers';
import { useCollectionContext } from '../CollectionContext';
import { observer } from 'mobx-react-lite';
import { FiltersMap } from '@wix/bex-core';
import { CollectionDragAndDropState, DragAndDropSubmit } from '../DragAndDrop';
import { sortableGridKeyboardCoordinates } from './sortableGridKeyboardCoordinates';
import { DragAndDropAnnouncements } from '../DragAndDrop/DragAndDropAnnouncements';
import { GridBaseState } from '../../state';
import { usePageContext } from '@wix/bex-core/react';

export interface GridSortableContextProps<T, F extends FiltersMap> {
  state: GridBaseState<T, F>;
  children?: ReactNode;
  onSubmit?: DragAndDropSubmit<T, F>;
}

function _GridSortableContext<T, F extends FiltersMap>(
  props: GridSortableContextProps<T, F>,
) {
  const { state: grid, children, onSubmit } = props;

  const collection = useCollectionContext();
  const { modalsContainerRef } = usePageContext();

  const {
    result: { keyedItems },
  } = collection;

  const state = grid.collectionDragAndDropState as CollectionDragAndDropState<
    T,
    F
  >;

  const pointerSensor = useSensor(PointerSensor, {
    activationConstraint: state.dnd.activationConstraint,
  });

  const [coordinateGetter] = useState(() =>
    sortableGridKeyboardCoordinates({ containerDistanceThreshold: 0.1 }),
  );

  const keyboardSensor = useSensor(KeyboardSensor, {
    keyboardCodes: state.dnd.keyboardCodes,
    coordinateGetter,
  });

  // in jsdom we mock drag-and-drop by setting a custom events to draggable elements
  const sensors = useSensors(
    ...(process.env.NODE_ENV === 'test' ? [] : [pointerSensor, keyboardSensor]),
  );

  useEffect(() => state.init(), []);

  state.dnd.onSubmit = onSubmit;

  return (
    <DndContext
      sensors={sensors}
      autoScroll={{
        activator: AutoScrollActivator.DraggableRect,
        freeze: true,
        acceleration: 4,
        threshold: {
          y: 0.01,
          x: 0.2,
        },
      }}
      accessibility={{
        container: modalsContainerRef.current as HTMLElement | undefined,
        announcements: state.dnd.nullAnnouncements,
        screenReaderInstructions: {
          draggable: '',
        },
        restoreFocus: false,
      }}
      collisionDetection={closestCenter}
      modifiers={[restrictToWindowEdges]}
      cancelDrop={(ev) => state.dnd.beforeDrop(ev)}
      onDragStart={(ev) => {
        state.dnd.onDragStart(ev);
      }}
      onDragMove={(ev) => {
        state.dnd.onDragMove(ev);
      }}
      onDragEnd={(ev) => {
        state.dnd.onDragEnd(ev);
      }}
      onDragCancel={() => {
        state.dnd.onDragCancel();
      }}
      onDragOver={(ev) => {
        state.dnd.onDragOver(ev);
      }}
    >
      <SortableContext items={keyedItems} strategy={rectSortingStrategy}>
        {children}
        <DragAndDropAnnouncements
          state={state.dnd}
          dataHook="grid-dnd-live-region"
        />
      </SortableContext>
    </DndContext>
  );
}

export const GridSortableContext = observer(_GridSortableContext);
