import React, { useState } from 'react';
import {
  closestCenter,
  closestCorners,
  CollisionDetection as CollisionDetectionType,
  DndContext,
  DragOverlay,
  KeyboardSensor,
  Modifiers,
  MouseSensor,
  rectIntersection,
  TouchSensor,
  Translate,
  UniqueIdentifier,
  useDraggable,
  useSensor,
  useSensors,
} from '@dnd-kit/core';

import { Draggable } from '../../SACalendar/dndComponents/Draggable';
import { Droppable } from '../../SACalendar/dndComponents/Droppable';
import { GridContainer } from '../../SACalendar/dndComponents/GridContainer';
import { Wrapper } from '../../SACalendar/dndComponents/Wrapper';

export default {
  title: 'Core/Droppable/useDroppable',
};

interface Props {
  collisionDetection?: CollisionDetectionType;
  containers?: string[];
  modifiers?: Modifiers;
  value?: string;
}
const defaultCoordinates = {
  x: 0,
  y: 0,
};

export function DroppableStory({
  containers = ['A'],
  collisionDetection,
  modifiers,
}: Props) {
  const [{ translate }, setTranslate] = useState<{
    initialTranslate: Translate;
    translate: Translate;
  }>({ initialTranslate: defaultCoordinates, translate: defaultCoordinates });
  const [isDragging, setIsDragging] = useState(false);
  const [parent, setParent] = useState<UniqueIdentifier | null>(null);
  const [initialWindowScroll, setInitialWindowScroll] = useState(
    defaultCoordinates
  );
  const item = <DraggableItem />;

  const activationConstraint = {
    delay: 250,
    tolerance: 5,
  };
  const mouseSensor = useSensor(MouseSensor, {
    activationConstraint,
  });
  const touchSensor = useSensor(TouchSensor, {
    activationConstraint,
  });
  const keyboardSensor = useSensor(KeyboardSensor, {});

  const sensors = useSensors(mouseSensor, touchSensor, keyboardSensor);
  return (
    <DndContext
      collisionDetection={collisionDetection}
      modifiers={parent === null ? undefined : modifiers}
      onDragStart={() => {
        setInitialWindowScroll({
          x: window.scrollX,
          y: window.scrollY,
        });
        setIsDragging(true);
      }}
      onDragEnd={({ over }) => {
        setParent(over ? over.id : null);
        setIsDragging(false);
        setTranslate(({ translate }) => {
          return {
            translate,
            initialTranslate: translate,
          };
        });
        setInitialWindowScroll(defaultCoordinates);
      }}
      onDragMove={({ delta }) => {
        setTranslate(({ initialTranslate }) => ({
          initialTranslate,
          translate: {
            x: initialTranslate.x + delta.x - initialWindowScroll.x,
            y: initialTranslate.y + delta.y - initialWindowScroll.y,
          },
        }));
      }}
      onDragCancel={() => {
        setIsDragging(false);
        setTranslate(({ initialTranslate }) => ({
          translate: initialTranslate,
          initialTranslate,
        }));
        setInitialWindowScroll(defaultCoordinates);
      }}
      sensors={sensors}
    >
      <Wrapper>
        <Wrapper style={{ width: 350, flexShrink: 0 }}>
          {parent === null ? item : null}
        </Wrapper>
        <GridContainer columns={2}>
          {containers.map((id) => (
            <Droppable key={id} id={id} dragging={isDragging}>
              {parent === id ? item : null}
            </Droppable>
          ))}
        </GridContainer>
      </Wrapper>
      <DragOverlay>
        {isDragging ? <Draggable dragging dragOverlay /> : null}
      </DragOverlay>
    </DndContext>
  );
}

interface DraggableProps {
  handle?: boolean;
}

export function DraggableItem({ handle }: DraggableProps) {
  const { isDragging, setNodeRef, listeners } = useDraggable({
    id: 'draggable-item',
  });

  return (
    <Draggable
      dragging={isDragging}
      ref={setNodeRef}
      handle={handle}
      listeners={listeners}
      style={{
        opacity: isDragging ? 0 : undefined,
      }}
    />
  );
}

export const BasicSetup = () => <DroppableStory />;

export const App = () => <DroppableStory containers={['A', 'B', 'C']} />;

export const CollisionDetectionAlgorithms = () => {
  const [{ algorithm }, setCollisionDetectionAlgorithm] = useState({
    algorithm: rectIntersection,
  });

  return (
    <>
      <DroppableStory
        collisionDetection={algorithm}
        containers={['A', 'B', 'C']}
      />
      <div
        style={{
          position: 'absolute',
          bottom: 20,
          left: 20,
          display: 'flex',
          flexDirection: 'column',
        }}
      >
        <h3>Collision detection algorithm</h3>
        <label>
          <input
            type="radio"
            value="rectIntersection"
            checked={algorithm === rectIntersection}
            onClick={() =>
              setCollisionDetectionAlgorithm({ algorithm: rectIntersection })
            }
          />
          Rect Intersection
        </label>
        <label>
          <input
            type="radio"
            value="closestCenter"
            checked={algorithm === closestCenter}
            onClick={() =>
              setCollisionDetectionAlgorithm({ algorithm: closestCenter })
            }
          />
          Closest Center
        </label>
        <label>
          <input
            type="radio"
            value="closestCorners"
            checked={algorithm === closestCorners}
            onClick={() =>
              setCollisionDetectionAlgorithm({ algorithm: closestCorners })
            }
          />
          Closest Corners
        </label>
      </div>
    </>
  );
};
