import React, { Component, Children, cloneElement, createContext, createRef } from 'react'
import classNames from 'classnames'
import './Boxes.less'

export const { Provider: BoxesContextProvider, Consumer: BoxesContext } = createContext({
  context: {},
  setOnSave: null,
})

export default class Boxes extends Component {
  container = createRef()
  state = {
    boxOpen: this.props.currentStep === -1 ? null : 0,
    currentStep: this.props.currentStep || 1,
    context: {}
  }
  componentDidMount () {
    const { boxOpen } = this.props
    if (boxOpen !== undefined) this.setState({ boxOpen })
  }
  static getDerivedStateFromProps ({ currentStep: nextStep }, { boxOpen, currentStep,  }) {
    if (nextStep > currentStep) {
      return {
        boxOpen: boxOpen + 1,
        currentStep: nextStep
      }
    }
    return null
  }
  setContext = (contextUpdated, next) => {
    const { context } = this.state
    this.setState({
      context: {
        ...context,
        ...contextUpdated,
      }
    }, next && next())
  }
  saveChangesBeforeClosing (next, boxOpening) {
    if (!this.onSave) return next()
    this.onSave((error) => {
      if (!error) {
        this.onSave = null
        next()
      }
    }, boxOpening)
  }
  setOnBoxSave = (onSave) => {
    this.onSave = onSave
  }
  nextStep = ({ box } = {}) => {
    const { currentStep, boxOpen } = this.state
    this.openBox({ boxOpen: boxOpen !== null ? boxOpen + 1 : box })(() => {
      this.setState({
        currentStep: currentStep + 1
      })
    })
  }
  closeBox = (next) => {
    const { onChange } = this.props

    this.saveChangesBeforeClosing(() => {
      if (next) next()
      this.setState({ boxOpen: null })
      onChange && onChange(null)
    })
  }
  openBox = ({ boxOpen }) => (next) => {
    const { onChange } = this.props

    this.saveChangesBeforeClosing(() => {
      this.setState({ boxOpen })
      if (next) next()
      onChange && onChange(boxOpen)
    }, boxOpen)
  }
  render () {
    const { className, children, defaultContext } = this.props
    const { boxOpen, currentStep, context } = this.state
    return (
      <BoxesContextProvider
        value={{
          context: {
            ...defaultContext,
            ...context
          },
          setContext: this.setContext,
          setOnBoxSave: this.setOnBoxSave
        }}
      >
        <div
          ref={this.container}
          className={classNames({
            [className]: className,
            Boxes: true
          })}
        >
          {Children
            .map(children, (box, index) => {
              if (!box) return null
              const { onSave, step, showContinue, showDone } = box.props
              const isStepAbove = !showDone && currentStep > step
              const isStepBelow = showDone && currentStep >= step
              const isCurrentStep = showContinue && currentStep === step
              if (currentStep !== -1 && currentStep < step) return null
              return cloneElement(box, {
                hide: index !== (this.props.boxOpen || boxOpen),
                nextStep: this.nextStep,
                closeBox: this.closeBox,
                showDone: currentStep === -1 || isStepBelow || isStepAbove,
                showContinue: isCurrentStep,
                openBox: this.openBox({ boxOpen: index })
              })
            })}
        </div>
      </BoxesContextProvider>
    )
  }
}
