import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Draggable from 'react-draggable'

import { DragHandle } from 'DragHandle'
import { ArrowBox, Container } from './styled'

/**
 * @component
 * @category Popup
 * @since 0.2.0
 */
class PopupBase extends Component {
  state = {
    dragged: false,
    pinnedPixel: this.props.pixel,
    transparent: false
  }

  onStart = () => {
    const { arrow, onPopupDragStart, pixel, transparentDuringDrag } = this.props
    // this hard sets the arrow direction at the time of initial drag
    const lastArrow = !this.state.dragged ? arrow : this.state.lastArrow
    const pinnedPixel = !this.state.dragged ? pixel : this.state.pinnedPixel

    this.setState({
      dragged: true,
      lastArrow,
      pinnedPixel,
      transparent: transparentDuringDrag
    })
    onPopupDragStart()
  }

  onStop = e => {
    const { pinnedPixel } = this.state

    this.setState({
      transparent: false
    })
    this.props.onPopupDragEnd({ ...e, pinnedPixel })
  }

  handleDrag = e => {
    this.props.onPopupDrag(e)
  }

  render () {
    const { arrow: arrowProp, children, draggable, height, inline, pixel: pixelProp, show, width } = this.props
    const { dragged, lastArrow, pinnedPixel, transparent } = this.state
    const arrowTranslator = {
      top: 'bottom',
      bottom: 'top',
      left: 'right',
      right: 'left',
      none: 'none'
    }
    const pixel = dragged ? pinnedPixel : pixelProp
    const arrow = dragged ? lastArrow : arrowProp

    return (
      <Draggable
        axis='both'
        bounds='parent'
        handle={'.popupHandleTag'}
        onDrag={this.handleDrag}
        onStart={this.onStart}
        onStop={this.onStop}>
        <Container
          arrow={arrow}
          height={height}
          inline={inline}
          pixel={pixel}
          show={show}
          transparent={transparent}
          width={width}>
          {draggable ? <DragHandle className='popupHandleTag' /> : null}
          {!dragged && <ArrowBox position={arrowTranslator[arrow]} />}
          {children}
        </Container>
      </Draggable>
    )
  }
}

PopupBase.defaultProps = {
  arrow: 'none',
  draggable: true,
  height: 'auto',
  inline: false,
  onPopupDrag: () => {},
  onPopupDragEnd: () => {},
  onPopupDragStart: () => {},
  pixel: [0, 0],
  show: false,
  transparentDuringDrag: true,
  width: 280
}

PopupBase.propTypes = {
  /** The position of the popup's arrow (`top`, `right`, `bottom`, `left` or `none`) */
  arrow: PropTypes.string,
  /** The content of the popup */
  children: PropTypes.oneOfType([
    PropTypes.arrayOf(PropTypes.node),
    PropTypes.node
  ]),
  draggable: PropTypes.bool,
  /** The height of the popup */
  height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  /** Render the component inline (without absolute positioning) */
  inline: PropTypes.bool,
  /** Callback fired during drags when draggable is true */
  onPopupDrag: PropTypes.func,
  /** Callback fired after a drag when draggable is true */
  onPopupDragEnd: PropTypes.func,
  /** Callback fired at the beginning of a drag when draggable is true */
  onPopupDragStart: PropTypes.func,
  /** The pixel coordinate where the popup should render */
  pixel: PropTypes.array,
  /** Show/hide the popup */
  show: PropTypes.bool,
  /** Set PopupBase to see-through during a drag when draggable is true */
  transparentDuringDrag: PropTypes.bool,
  /** The width of the popup */
  width: PropTypes.number
}

export default PopupBase