/** @jsxRuntime classic */
/** @jsx jsx */

import {
  FC,
  useEffect,
  useMemo,
  useRef,
  useState,
  MutableRefObject,
} from 'react';
import { jsx } from '@emotion/react';
import { useDraggable } from '@dnd-kit/core';
import dayjs from 'dayjs';
import {
  calculateMarginFromMinutes,
  calculateMinutesFromHeight,
} from '../../utils/timeUtils';
import { useMiddlewareContext } from '../../hooks/useMiddlewareContext';
import { useDebouncedValue } from '../../hooks/useDebouncedValue';
import { useResize } from '../../hooks/useResize';
import { IDraggableDayToDropProps } from '../../types';
import {
  draggableContainer,
  draggableContent,
  draggableHandler,
  draggableResizeHandler,
} from '../styles';
import { DndIcon } from '../../utils/DndIcon';
import { getMinutesDifferenceByStep } from '../../utils';

export const Draggable: FC<IDraggableDayToDropProps> = ({
  children,
  id,
  state,
  parentId,
  groupTop,
  groupCount,
  groupIndex,
}) => {
  const elementId = `draggable-${id}`;

  const { updateDatesRange, getTopAndHeight, options } = useMiddlewareContext();

  const { top, height } = useMemo(
    () =>
      getTopAndHeight(
        dayjs.utc(state.startDate).toDate().getTime(),
        dayjs.utc(state.endDate).toDate().getTime()
      ),
    [state.startDate, state.endDate]
  );

  const { isDragging, setNodeRef, listeners } = useDraggable({
    id: String(id),
    data: {
      parentId: parentId,
      event: state,
    },
  });

  const ref = useRef<HTMLDivElement>() as MutableRefObject<HTMLDivElement>;
  const { initResize, size, cursor } = useResize(
    ref as MutableRefObject<HTMLDivElement>,
    {
      axis: 'vertical',
    }
  );
  const sizeH = useDebouncedValue(size.height, 200);

  const [sizeHeight, setSizeHeight] = useState(size.height);

  useEffect(() => {
    setSizeHeight(sizeH);
  }, [sizeH]);

  const handleResize = () => {
    const draggableElement = ref?.current;
    if (!isDragging && draggableElement && !Number.isNaN(sizeHeight)) {
      const draggableHeight = draggableElement.offsetHeight;
      if (draggableHeight !== sizeHeight) return;

      const startDate = state?.startDate;
      let minutes = Math.floor(calculateMinutesFromHeight(draggableHeight));

      minutes = getMinutesDifferenceByStep(
        startDate,
        minutes,
        options.dndStepLength,
        true
      );

      const endDate = dayjs
        .utc(startDate)
        .add(minutes, 'minute')
        .set('milliseconds', 0)
        .set('seconds', 0)
        .toISOString();

      const onChangeData = {
        type: 'SLOT_RESIZE',
        data: {
          startDate,
          endDate,
          startTime: dayjs.utc(startDate).format('HH:mm'),
          endTime: dayjs.utc(endDate).format('HH:mm'),
          parentId,
          slotId: String(state.id),
        },
      };

      draggableElement.removeAttribute('style');
      setSizeHeight(calculateMarginFromMinutes(minutes));

      updateDatesRange(state.id, startDate, endDate, onChangeData);
    }
  };

  useEffect(() => {
    handleResize();
  }, [sizeHeight]);

  return (
    <div
      id={elementId}
      css={draggableContainer(top - (groupTop || 0), groupCount, groupIndex)}
      ref={setNodeRef}
    >
      <div
        css={draggableContent(
          !Number.isNaN(sizeHeight) && sizeHeight !== Infinity
            ? sizeHeight
            : height
        )}
        ref={ref}
      >
        {children}
        {options.dragAndDrop && (
          <div {...listeners} css={draggableHandler}>
            <DndIcon />
          </div>
        )}
        {options.resize && (
          <div css={draggableResizeHandler(cursor)} onMouseDown={initResize} />
        )}
      </div>
    </div>
  );
};
