import React, { Component } from 'react'

import List from '@material-ui/core/List'
import LayerPanelListItem from 'LayerPanel/LayerPanelListItem'
import nanoid from 'nanoid'
import PropTypes from 'prop-types'

const applyDrag = (arr, dragResult) => {
  const { removedIndex, addedIndex, payload } = dragResult

  if (removedIndex === null && addedIndex === null) return arr

  const result = [...arr]

  let itemToAdd = payload

  if (removedIndex !== null) {
    itemToAdd = result.splice(removedIndex, 1)[0]
  }

  if (addedIndex !== null) {
    result.splice(addedIndex, 0, itemToAdd)
  }

  return result
}

/**
 * @component
 * @category LayerPanel
 * @since 0.5.0
 */
class LayerPanelList extends Component {
  handleDrop = e => {
    const { onSort, onReorderedItems, items, onLayerReorder } = this.props
    const reorderedItems = applyDrag(items.sort(onSort), e)

    if (onReorderedItems) {
      onReorderedItems(reorderedItems)
      onLayerReorder()
    }
  }

  onDragOver = e => {
    e.preventDefault()
    e.dataTransfer.dropEffect = 'move'
    let dropNode = e.target

    do {
      if (dropNode.className === 'dropzone') {
        this.displaced = dropNode.firstChild
        this.dragTarget.parentNode.replaceChild(dropNode.firstChild, this.dragTarget)
        dropNode.appendChild(this.dragTarget)

        break
      }
    }
    while (dropNode = dropNode.parentNode, (dropNode.id !== '_ol_kit_layer_panel_drag_container' && dropNode.id !== this.dragTarget.id)) // eslint-disable-line
  }

  onDragStart = e => {
    e.dataTransfer.dropEffect = 'move'
    this.dragTarget = e.target
    e.target.style.opacity = '0.25'
  }

  onDragEnd = e => {
    e.preventDefault()
    let dropNode = e.target

    do {
      if (dropNode.className === 'draggable') {
        const removedIndex = parseInt(this.dragTarget.id.split('_')[0])
        const addedIndex = parseInt(this.displaced.id.split('_')[0])
        const payload = this.dragTarget

        this.handleDrop({ ...e, removedIndex, addedIndex, payload })

        break
      }
    }
    while (dropNode = dropNode.parentNode, dropNode.id !== '_ol_kit_layer_panel_drag_container') // eslint-disable-line

    this.dragTarget.style.opacity = '1'
  }

  render () {
    const { children, disableDrag, items } = this.props

    if (children) {
      return (
        <List>
          <div id='_ol_kit_layer_panel_drag_container' onDragEnd={this.onDragEnd} >
            {React.Children.map(this.props.children, (child, i) => {
              const id = `${i}_${nanoid(6)}`

              return (
                <div className={'dropzone'} onDragOver={this.onDragOver} key={id || child.id} >
                  <div id={id} className={'draggable'} draggable={!disableDrag} onDragStart={this.onDragStart} onMouseEnter={() => this.addInteraction} >{child}</div>
                </div>
              )
            })}
          </div>
        </List>
      )
    } else if (items) {
      return (
        <List>
          <div id='_ol_kit_layer_panel_drag_container' onDragEnd={this.onDragEnd}>
            {items.map((item, i) => {
              const id = `${i}_${nanoid(6)}`

              return (
                <div className={'dropzone'} onDragOver={this.onDragOver} key={item}>
                  <div id={id} className={'draggable'} draggable={!disableDrag} onDragStart={this.onDragStart} >
                    <LayerPanelListItem onMouseOver={() => this.addInteraction}>{item}</LayerPanelListItem>
                  </div>
                </div>
              )
            }
            )}
          </div>
        </List>
      )
    } else {
      return <div>Must either pass `children` or a prop of `items` for LayerPanelList to render its list</div>
    }
  }
}

LayerPanelList.propTypes = {
  /** The content of the LayerPanelList (likely `LayerPanelListItem` components) */
  children: PropTypes.node,

  /** callback when item prop is dropped */
  onSort: PropTypes.func,

  /** callback with reordered items */
  onReorderedItems: PropTypes.func,

  /** array of items to be rendered in the list */
  items: PropTypes.array,

  /** A boolean to disable the drag event on the LayerPanelList */
  disableDrag: PropTypes.bool,

  /** A callback function to inform when the list is reordered */
  onLayerReorder: PropTypes.func
}

LayerPanelList.defaultProps = {
  onSort: (a, b) => { return a - b },
  disableDrag: false,
  onLayerReorder: () => {}
}

export default LayerPanelList