import * as React from 'react';
import { action } from 'mobx';
import * as d3 from 'd3';
import { observer } from 'mobx-react';
import Point from '../geom/Point';
import EntityContext from '../utils/EntityContext';
import { isEdgeEntity, PointTuple } from '../types';
import {
  ConnectDragSource,
  DragSourceSpec,
  DragEvent,
  DragObjectWithType,
  DragSourceMonitor,
} from './dnd-types';
import { useDndDrag, WithDndDragProps } from './dndDrag';

export const useAddBendpoint = (): any => {
  const entity = React.useContext(EntityContext);
  if (!isEdgeEntity(entity)) {
    throw new Error('useAddBendpoint must be used within the scope of an EdgeEntity');
  }
  const entityRef = React.useRef(entity);
  entityRef.current = entity;

  const [point, setPoint] = React.useState<PointTuple | null>(null);

  // argh react events don't play nice with d3 pan zoom double click event
  const ref = React.useCallback((node) => {
    d3.select(node).on('mouseover.addBendpoint', () => {
      if (d3.event.shiftKey) {
        d3.event.stopPropagation();
        entityRef.current.removeBendpoint(pointRef.current);
      }
    });
    dragRef(node);
  }, []);
  return [point, ref];
};

type HocProps = {
  point: Point;
};

export type WithBendpointProps = {
  dragNodeRef: WithDndDragProps['dndDragRef'];
};

export const WithBendpoint = <DropResult, CollectedProps, Props = {}>(
  spec?: Omit<DragSourceSpec<DragObjectWithType, DropResult, CollectedProps, Props>, 'type'>,
) => <P extends WithBendpointProps & CollectedProps & Props>(
  WrappedComponent: React.ComponentType<P>,
) => {
  const Component: React.FC<Omit<P, keyof WithBendpointProps> & HocProps> = (props) => {
    const [dragProps, bendpointRef] = useBendpoint(props.point, spec, props);
    return <WrappedComponent {...props as any} bendpointRef={bendpointRef} {...dragProps} />;
  };
  return observer(Component);
};
