import React, { ReactNode, useEffect } from 'react';
import {
  AutoScrollActivator,
  closestCenter,
  DndContext,
  DragEndEvent,
  DragStartEvent,
  KeyboardSensor,
  PointerSensor,
  useSensor,
  useSensors,
} from '@wix/wix-style-react-incubator/dnd-kit/core';
import { restrictToWindowEdges } from '@wix/wix-style-react-incubator/dnd-kit/modifiers';
import { observer } from 'mobx-react-lite';
import { FiltersMap } from '@wix/bex-core';
import { KanbanState } from '../../state/KanbanState/KanbanState';

import { usePageContext } from '@wix/bex-core/react';

export interface KanbanDragAndDropContextProps<T, S, F extends FiltersMap> {
  state: KanbanState<T, S, F>;
  children?: ReactNode;
  stageId: string;
}

function _KanbanDragAndDropContext<T, S, F extends FiltersMap>(
  props: KanbanDragAndDropContextProps<T, S, F>,
) {
  const { state: kanbanState, children } = props;

  const { modalsContainerRef } = usePageContext();

  const dragAndDropState = kanbanState.dragAndDropState;

  const pointerSensor = useSensor(PointerSensor, {
    activationConstraint: {
      distance: 3,
    },
  });

  const keyboardSensor = useSensor(KeyboardSensor, {
    keyboardCodes: kanbanState.dragAndDropState.keyboardCodes,
    coordinateGetter: () => ({ x: 0, y: 25 }),
  });

  const sensors = useSensors(
    ...(process.env.NODE_ENV === 'test' ? [] : [pointerSensor, keyboardSensor]),
  );

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

  const handleDragStart = (event: DragStartEvent) => {
    dragAndDropState.handleDragStart(event);
  };

  const handleDragOver = () => {};

  const handleDragEnd = (event: DragEndEvent) => {
    dragAndDropState.handleDragEnd(event);
  };

  const handleDragCancel = () => {
    dragAndDropState.handleDragCancel();
  };

  return (
    <DndContext
      sensors={sensors}
      autoScroll={{
        activator: AutoScrollActivator.DraggableRect,
        acceleration: 1,
        interval: 10,
        threshold: {
          y: 0.15,
          x: 0.15,
        },
      }}
      accessibility={{
        container: modalsContainerRef.current as HTMLElement | undefined,
        announcements: {
          onDragStart: () => 'Item picked up for dragging',
          onDragOver: () => 'Item moved over droppable area',
          onDragEnd: () => 'Item dropped',
          onDragCancel: () => 'Dragging cancelled',
        },
        screenReaderInstructions: {
          draggable: 'To pick up a draggable item, press the space bar.',
        },
        restoreFocus: false,
      }}
      collisionDetection={closestCenter}
      modifiers={[restrictToWindowEdges]}
      onDragStart={handleDragStart}
      onDragOver={handleDragOver}
      onDragEnd={handleDragEnd}
      onDragCancel={handleDragCancel}
    >
      {children}
    </DndContext>
  );
}

export const KanbanDragAndDropContext = observer(_KanbanDragAndDropContext);
