import React, { Component } from 'react'
import { DragDropContext, DragSource, DropTarget } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'

// 可拖曳列表
let dragingIndex = -1

const rowSource = {
  beginDrag (props) {
    dragingIndex = props.index
    return {
      index: props.index
    }
  }
}

const rowTarget = {
  drop (props, monitor) {
    const dragIndex = monitor.getItem().index
    const hoverIndex = props.index

    // Don't replace items with themselves
    if (dragIndex === hoverIndex) {
      return
    }

    // Time to actually perform the action
    props.moveRow(dragIndex, hoverIndex)

    // Note: we're mutating the monitor item here!
    // Generally it's better to avoid mutations,
    // but it's good here for the sake of performance
    // to avoid expensive index searches.
    monitor.getItem().index = hoverIndex
  },
}

class BodyRow extends Component {
  render () {
    const { isOver, connectDragSource, connectDropTarget, moveRow, ...restProps } = this.props
    const style = { ...restProps.style, cursor: 'move' }

    let { className } = restProps
    if (isOver) {
      if (restProps.index > dragingIndex) {
        className += ' drop-over-downward'
      }
      if (restProps.index < dragingIndex) {
        className += ' drop-over-upward'
      }
    }

    return connectDragSource(
      connectDropTarget(<tr {...restProps} className={className} style={style} />),
    )
  }
}

const DragableBodyRow = DropTarget('row', rowTarget, (connect, monitor) => ({
  connectDropTarget: connect.dropTarget(),
  isOver: monitor.isOver()
}))(
  DragSource('row', rowSource, connect => ({
    connectDragSource: connect.dragSource()
  }))(BodyRow)
)

export function getDragableProps (moveRow) {
  return {
    components: {
      body: {
        row: DragableBodyRow
      }
    },
    onRow: (record, index) => ({
      index,
      moveRow
    })
  }
}

// 可拖曳卡片
const cardSource = {
  beginDrag (props) {
    dragingIndex = props.index
    return {
      index: props.index
    }
  }
}

const connectSource = (connect) => {
  return {
    connectDragSource: connect.dragSource()
  }
}

const cardTarget = {
  drop (props, monitor) {
    const dragIndex = monitor.getItem().index
    const hoverIndex = props.index

    if (dragIndex === hoverIndex) {
      return
    }

    props.moveRow instanceof Function && props.moveRow(dragIndex, hoverIndex)

    monitor.getItem().index = hoverIndex
  }
}

const connectTarget = (connect, monitor) => {
  return {
    connectDropTarget: connect.dropTarget(),
    isOver: monitor.isOver()
  }
}

class DragableCard extends Component {
  render () {
    const { isOver, connectDragSource, connectDropTarget, index, children } = this.props

    let { className, style } = children.props
    if (isOver) {
      if (index > dragingIndex) {
        className += ' drop-over-rightward'
      }
      if (index < dragingIndex) {
        className += ' drop-over-leftward'
      }
    }

    return connectDragSource(
      connectDropTarget(React.cloneElement(children, { className, style: { ...style, cursor: 'move' } }))
    )
  }
}

const dragableCardType = 'Card'
export const DragDropCard = DropTarget(dragableCardType, cardTarget, connectTarget)(
  DragSource(dragableCardType, cardSource, connectSource)(DragableCard)
)

export default DragDropContext(HTML5Backend)