import React, { useRef } from 'react';
import PropTypes from 'prop-types';
import { Draggable } from 'react-beautiful-dnd';
import { useDragContainerContext } from './PipelineDragContainer';
import { useMapInteractionContext } from '../mapInteraction/MapInteractionContext';

const propTypes = {
  children: PropTypes.node,
  id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
  index: PropTypes.number.isRequired,
};
const defaultProps = {
  children: '',
};

const getOffset = (el, offset = { top: 0, left: 0 }) => {
  if (!el) {
    return offset;
  }

  const newOffset = {
    top: offset.top + el.offsetTop,
    left: offset.left + el.offsetLeft,
  };

  return getOffset(el.offsetParent, newOffset);
};

export const PipelineDragItem = ({
  children, id, index,
}) => {
  const baseItemStyleOnDrag = useRef({
    top: 0,
    left: 0,
  });
  const { containerEl, setPlaceholderStyle } = useDragContainerContext();
  const mapContext = useMapInteractionContext();
  const scale = mapContext ? mapContext.scale : 1;
  const isFirstStyleCompute = useRef(true);
  const itemRef = useRef();
  const itemEl = itemRef.current;

  const updateStyle = () => {
    if (!containerEl || !itemEl || !isFirstStyleCompute.current) {
      return;
    }

    const containerRect = getOffset(containerEl);
    const itemRect = getOffset(itemEl);

    setPlaceholderStyle({
      width: itemEl.offsetWidth,
      height: itemEl.offsetHeight,
    });

    baseItemStyleOnDrag.current = {
      top: itemRect.top - containerRect.top,
      left: itemRect.left - containerRect.left,
      width: itemEl.offsetWidth,
      height: itemEl.offsetHeight,
    };
  };

  const getStyle = (style, isDragging) => {
    const { transform } = style;

    const translateRegex = /translate\((?<x>-?[0-9.]*)[px]*,\s?(?<y>-?[0-9.]*)[px]*\)/g;
    const { x, y } = (translateRegex.exec(transform) || {}).groups || {};
    const newTransform = `translate(${(x || 0) / scale}px, ${(y || 0) / scale}px)`;

    if (!isDragging) {
      isFirstStyleCompute.current = true;
      return {
        ...style,
        transform: newTransform,
      };
    }

    updateStyle();
    isFirstStyleCompute.current = false;

    return {
      ...style,
      ...baseItemStyleOnDrag.current,
      position: 'absolute',
      transform: newTransform,
    };
  };

  return (
    <Draggable draggableId={id} index={index}>
      {(provided, snapshot) => (
        <div
          ref={(el) => {
            provided.innerRef(el);
            itemRef.current = el;
          }}
          className="sui-prj-pipeline-drag-item"
          {...provided.draggableProps}
          {...provided.dragHandleProps}
          style={getStyle(provided.draggableProps.style, snapshot.isDragging)}
        >
          {children}
        </div>
      )}
    </Draggable>
  );
};

PipelineDragItem.propTypes = propTypes;
PipelineDragItem.defaultProps = defaultProps;
