import { useSortable } from '@wix/wix-style-react-incubator/dnd-kit/sortable';
import React, { HTMLAttributes, useEffect, useRef } from 'react';
import { CSS } from '@wix/wix-style-react-incubator/dnd-kit/utilities';
import { Box } from '@wix/design-system';
import { DraggableCardProps, GridCardItemProps } from '../DragAndDrop';
import { FiltersMap } from '@wix/bex-core';
import { observer } from 'mobx-react-lite';
import {
  dragHandleTestEvents,
  sortableItemTestEvents,
} from './dndTestEventHandlers';
import { addEventListener } from '@wix/bex-core/util';

function _GridDraggableCardItem<T, F extends FiltersMap>(
  props: DraggableCardProps<T, F>,
) {
  const { children, id, isOverlay, state } = props;
  const { type: CardItem, props: forwardCardItemProps } = children;
  const { _dnd } = state;

  const isDropping = _dnd?.droppingId === id;

  const dragHandleRef = useRef<HTMLElement | null>(null);

  useEffect(() => {
    if (_dnd) {
      return addEventListener(_dnd.events, 'dropAnimationEnd', () => {
        _dnd.focusDragHandleIfDropped(id, dragHandleRef.current);
      });
    }

    return;
  }, [id, _dnd]);

  const {
    attributes,
    listeners,
    setNodeRef,
    transform,
    transition,
    isDragging,
    setActivatorNodeRef,
  } = useSortable({
    id,
    transition: _dnd?.sortableAnimation,
    disabled: {
      draggable: false,
      droppable: _dnd?.isActiveRectOutsideContainer,
    },
  });

  const showMask = (isDragging || isDropping) && !isOverlay;

  const ariaDescribedBy = `draggable-card-item-description-${id}`;

  const dragHandleProps: GridCardItemProps['dragHandleProps'] = isOverlay
    ? {}
    : {
        tabIndex: 0,
        domRef: (e) => {
          setActivatorNodeRef(e);
          dragHandleRef.current = e;
          _dnd?.focusDragHandleIfDropped(id, dragHandleRef.current);
        },
        role: 'button',
        'aria-label': _dnd?.nullAnnouncements?.dragHandleLabel?.(id),
        'aria-describedby': ariaDescribedBy,
        onClick: (e) => e.stopPropagation(),
        ..._dnd?.handleEvents,
        ...(process.env.NODE_ENV === 'test' &&
          state._dnd &&
          dragHandleTestEvents({ id, state: state._dnd })),
      };

  const cardItemProps: GridCardItemProps = {
    ...forwardCardItemProps,
    ...(_dnd?.isDisabled
      ? {}
      : {
          draggable: true,
          droppable: _dnd?.isActive,
          dragging: isOverlay,
          dragHandleProps,
        }),
  };

  const style = {
    position: 'relative' as const,
    height: '100%',
    width: '100%',
    transform: CSS.Transform.toString(transform),
    transition,
    ...(_dnd?.isDropping && { transition: undefined }),
  };

  const testEvents =
    process.env.NODE_ENV === 'test' && state._dnd
      ? sortableItemTestEvents({ id, state: state._dnd })
      : undefined;

  const dndAttrs: Partial<HTMLAttributes<HTMLDivElement>> = _dnd?.isDisabled
    ? {
        onPointerDown: (e) => {
          _dnd?.attachDisabledDragAttempt(id, e.nativeEvent, 'all');
        },
      }
    : {
        ...attributes,
        ...listeners,
        ...testEvents,
        onPointerDown: (e) => {
          state._dnd?.containerEvents.onPointerDown?.(e);
          listeners?.onPointerDown?.(e);
          testEvents?.onPointerDown?.(e);
        },
      };

  return (
    <div
      ref={setNodeRef}
      style={style}
      {...dndAttrs}
      tabIndex={undefined}
      data-hook="grid-card-item-events"
    >
      <div id={ariaDescribedBy} style={{ display: 'none' }}>
        {state._dnd?.nullAnnouncements?.itemDescription?.(id)}
      </div>
      {!showMask && <CardItem {...cardItemProps} />}
      {showMask && (
        <Box
          borderRadius={8}
          height="100%"
          width="100%"
          backgroundColor="D60"
        />
      )}
    </div>
  );
}

export const GridDraggableCardItem = observer(_GridDraggableCardItem);
