import Component from 'inferno-component'
import createElement from 'inferno-create-element'
import { View, throwError } from 'cerebral'

class BaseComponent extends Component {
  constructor(dependencies, mergeProps, props, controller, name) {
    super(props)
    if (!controller) {
      throwError(
        'Can not find controller, did you remember to use the Container component? Read more at: https://cerebraljs.com/docs/views/inferno.html'
      )
    }

    this._propsChange = false
    this.onUpdate = this.onUpdate.bind(this)
    this.view = new View({
      dependencies,
      mergeProps,
      props,
      controller,
      displayName: name,
      onUpdate: this.onUpdate,
    })
  }
  /*
    Register the component to the dependency store with its
    state tracker and tags state dependencies
  */
  componentWillMount() {
    this.view.mount()
  }
  /*
    We only allow forced render by change of props passed
    or Container tells it to render
  */
  shouldComponentUpdate() {
    if (this._propsChange) {
      this._propsChange = false
      return true
    }
    return false
  }
  /*
    If received props differ, we need to update any
    StateTrackers and tags, cause they might be using
    props to define a state dependency
  */
  componentWillReceiveProps(nextProps) {
    const hasUpdate = this.view.onPropsUpdate(this.props, nextProps)
    if (hasUpdate) {
      this.forceUpdate()
      this._propsChange = true
    }
  }
  /*
    Unregister with existing state dependencies
  */
  componentWillUnmount() {
    this.view.unMount()
  }
  onUpdate(stateChanges, force) {
    this.view.updateFromState(stateChanges, this.props, force)
    this.forceUpdate()
  }
}

export default function HOC(dependencies, mergeProps, Component) {
  class CerebralComponent extends BaseComponent {
    constructor(props, context) {
      super(
        dependencies,
        mergeProps,
        props,
        context.controller,
        Component.displayName || Component.name
      )
    }
    toJSON() {
      return this.view._displayName
    }
    render() {
      return createElement(Component, this.view.getProps(this.props))
    }
  }
  CerebralComponent.displayName = `CerebralWrapping_${Component.displayName ||
    Component.name}`

  return CerebralComponent
}

import Component from 'inferno-component'
import createElement from 'inferno-create-element'
import { View, throwError } from 'cerebral'

class BaseComponent extends Component {
  constructor(dependencies, mergeProps, props, controller, name) {
    super(props)
    if (!controller) {
      throwError(
        'Can not find controller, did you remember to use the Container component? Read more at: https://cerebraljs.com/docs/views/inferno.html'
      )
    }

    this._propsChange = false
    this.onUpdate = this.onUpdate.bind(this)
    this.view = new View({
      dependencies,
      mergeProps,
      props,
      controller,
      displayName: name,
      onUpdate: this.onUpdate,
    })
  }
  /*
    Register the component to the dependency store with its
    state tracker and tags state dependencies
  */
  componentDidMount() {
    this.view.mount()
  }
  /*
    We only allow forced render by change of props passed
    or Container tells it to render
  */
  shouldComponentUpdate() {
    if (this._propsChange) {
      this._propsChange = false
      return true
    }
    return false
  }
  /*
    If received props differ, we need to update any
    StateTrackers and tags, cause they might be using
    props to define a state dependency
  */
  componentWillReceiveProps(nextProps) {
    const hasUpdate = this.view.onPropsUpdate(this.props, nextProps)
    if (hasUpdate) {
      this.forceUpdate()
      this._propsChange = true
    }
  }
  /*
    Unregister with existing state dependencies
  */
  componentWillUnmount() {
    this.view.unMount()
  }
  onUpdate(stateChanges, force) {
    this.view.updateFromState(stateChanges, this.props, force)
    this.forceUpdate()
  }
}

export default function HOC(dependencies, mergeProps, Component) {
  class CerebralComponent extends BaseComponent {
    constructor(props, context) {
      super(
        dependencies,
        mergeProps,
        props,
        context.controller,
        Component.displayName || Component.name
      )
    }
    toJSON() {
      return this.view._displayName
    }
    render() {
      return createElement(Component, this.view.getProps(this.props))
    }
  }
  CerebralComponent.displayName = `CerebralWrapping_${Component.displayName ||
    Component.name}`

  return CerebralComponent
}

change render hook for SSR