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

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

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

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

  const { top, height } = useMemo(
    () =>
      getTopAndHeight(
        dayjs.utc(state.startDate).toDate().getTime(),
        dayjs.utc(state.endDate).toDate().getTime(),
        true
      ),
    [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: 'horizontal',
    }
  );
  const sizeW = useDebouncedValue(size.width, 200);

  const [sizeWidth, setSizeWidth] = useState(size.width);

  useEffect(() => {
    setSizeWidth(sizeW);
  }, [sizeW]);

  const handleResize = () => {
    const draggableElement = ref?.current;
    if (!isDragging && draggableElement && !Number.isNaN(sizeWidth)) {
      const draggableWidth = draggableElement.offsetWidth;
      if (draggableWidth !== sizeWidth) return;

      const startDate = state?.startDate;
      let minutes = Math.floor(calculateMinutesFromWidth(draggableWidth));

      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');
      setSizeWidth(calculateMarginLeftFromMinutes(minutes));

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

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

  if (top + height > oneHourWidth * 24 * daysCount + 6) return null;

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