import React, { Component, PropTypes } from 'react';
import { findDOMNode } from 'react-dom';
import { DragSource, DropTarget } from 'react-dnd';

const Types = { CARD: 'card' };
/**
 * Specifies the drop target contract.
 * All methods are optional.
 */
const cardTarget = {
  canDrop(props, monitor) {
    // You can disallow drop based on props or item
    // const item = monitor.getItem();
    return props.droppable;
  },

  hover(props, monitor, component) {
    // This is fired very often and lets you perform side effects
    // in response to the hover. You can't handle enter and leave
    // here—if you need them, put monitor.isOver() into collect() so you
    // can just use componentWillReceiveProps() to handle enter/leave.

    // You can access the coordinates if you need them
    const clientOffset = monitor.getClientOffset();
    const componentRect = findDOMNode(component).getBoundingClientRect();

    // You can check whether we're over a nested drop target
    const isJustOverThisOne = monitor.isOver({ shallow: true });

    // You will receive hover() even for items for which canDrop() is false
    const canDrop = monitor.canDrop();
  },

  drop(props, monitor, component) {
    if (monitor.didDrop()) {
      // If you want, you can check whether some nested
      // target already handled drop
      return;
    }

    // Obtain the dragged item
    const item = monitor.getItem();

    // You can do something with it
    // ChessActions.movePiece(item.fromPosition, props.position);

    // You can also do nothing and return a drop result,
    // which will be available as monitor.getDropResult()
    // in the drag source's endDrag() method
    // debugger;
    return { moved: true, index: props.index, column: props.column };
  },
};

/**
 * Specifies the drag source contract.
 * Only `beginDrag` function is required.
 */
const cardSource = {
  canDrag(props) {
    // You can disallow drag based on props
    return props.draggable;
  },

  isDragging(props, monitor) {
    // If your component gets unmounted while dragged
    // (like a card in Kanban board dragged between lists)
    // you can implement something like this to keep its
    // appearance dragged:
    return monitor.getItem().title === props.title;
  },

  beginDrag(props, monitor, component) {
    // Return the data describing the dragged item
    const { title, column, index, tab, size } = props;
    const childTitle = props.children.props.title;
    const item = { title, column, index, tab, size, childTitle };
    return item;
  },

  endDrag(props, monitor, component) {
    if (!monitor.didDrop()) {
      // You can check whether the drop was successful
      // or if the drag ended but nobody handled the drop
      return;
    }

    // When dropped on a compatible target, do something.
    // Read the original dragged item from getItem():
    const item = monitor.getItem();

    // You may also read the drop result from the drop target
    // that handled the drop, if it returned an object from
    // its drop() method.
    const dropResult = monitor.getDropResult();
    const tab = item.tab;
    const size = item.size;
    const from = { column: item.column, index: item.index };
    const to = { column: dropResult.column, index: dropResult.index };
    const eventPayload = {
      category: 'Drag and Drop',
      action: `Moved ${item.title || item.childTitle}`,
      label: `From ${item.column}-${item.index} to ${dropResult.column}-${dropResult.index}`,
    };
    props.ReactGA.event(eventPayload);
    props.moveCard(tab, size, from, to);
  },
};

/**
 * Specifies which props to inject into your component.
 */
function dragCollect(connect, monitor) {
  return {
    // Call this function inside render()
    // to let React DnD handle the drag events:
    canDrag: monitor.canDrag(),
    connectDragSource: connect.dragSource(),
    // You can ask the monitor about the current drag state:
    isDragging: monitor.isDragging(),
  };
}

function dropCollect(connect, monitor) {
  return {
    connectDropTarget: connect.dropTarget(),
    isOver: monitor.isOver(),
  };
}

class DNDContainer extends Component {
  render() {
    const {
      connectDragSource,
      isOver,
      canDrop,
      connectDropTarget,
      draggable,
      droppable,
      style,
    } = this.props;

    return connectDragSource(
      connectDropTarget(<div style={style}>{this.props.children}</div>),
    );
  }
}

DNDContainer.propTypes = {
  droppable: PropTypes.bool,
  draggable: PropTypes.bool,
  connectDragSource: PropTypes.func,
  connectDropTarget: PropTypes.func,
  canDrag: PropTypes.bool,
  canDrop: PropTypes.bool,
  draggable: PropTypes.bool,
  droppable: PropTypes.bool,
  children: PropTypes.object,
  style: PropTypes.objectOf(PropTypes.string),
};

DNDContainer.defaultProps = {
  droppable: true,
  draggable: true,
};

export default DropTarget(Types.CARD, cardTarget, dropCollect)(
  DragSource(Types.CARD, cardSource, dragCollect)(DNDContainer),
);
