/* eslint-disable no-console */
import {Component, PropTypes} from 'react';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
import createEagerFactory from 'recompose/createEagerFactory';
import createHelper from './createHelper';
import createSymbol from './utils/createSymbol';

const throwError = (error) => {
  throw error;
};

const MAPPERS_INFO = createSymbol('mappersInfo');
const OBSERVABLES = createSymbol('observables');

const createComponentFromMappers = (mappers, BaseComponent) => {
  const factory = createEagerFactory(BaseComponent);

  return class extends Component {
    static [MAPPERS_INFO] = {mappers, BaseComponent};
    static contextTypes = {[OBSERVABLES]: PropTypes.object};
    static childContextTypes = {[OBSERVABLES]: PropTypes.object};

    props$ = new BehaviorSubject(this.props);

    getChildContext() {
      return this.childContext;
    }

    componentWillMount() {
      const {
        props$: childProps$,
        ...childObservables
      } = mappers.reduce(
        (observables, mapper) => ({
          props$: this.props$,
          ...mapper(observables),
        }),
        {
          ...this.context[OBSERVABLES],
          props$: this.props$,
        },
      );

      this.subscription = childProps$.subscribe({
        next: childProps => this.setState({childProps}),
        error: throwError,
      });

      this.childContext = {[OBSERVABLES]: childObservables};
    }

    componentWillReceiveProps(nextProps) {
      this.props$.next(nextProps);
    }

    componentWillUnmount() {
      this.subscription.unsubscribe();
    }

    shouldComponentUpdate(nextProps, nextState) {
      return this.state.childProps !== nextState.childProps;
    }

    render() {
      if (!this.state.childProps) {
        return null;
      }

      return factory(this.state.childProps);
    }
  };
};

export default createHelper(mapper => (BaseComponent) => {
  if (BaseComponent[MAPPERS_INFO]) {
    return createComponentFromMappers(
      [mapper, ...BaseComponent[MAPPERS_INFO].mappers],
      BaseComponent[MAPPERS_INFO].BaseComponent,
    );
  }

  return createComponentFromMappers([mapper], BaseComponent);
}, 'mapObs');

@@ -479,90 +479,26 @@
 rs, 
-BaseComponent) =%3E %7B%0A  const f
+childF
 actory
+)
  =
- createEagerFactory(BaseComponent);%0A%0A  return
+%3E%0A 
  cla
@@ -558,29 +558,28 @@
 appers, 
-BaseComponent
+childFactory
 %7D;%0A    s
@@ -1735,17 +1735,53 @@
  return 
-f
+this.constructor%5BMAPPERS_INFO%5D.childF
 actory(t
@@ -1813,19 +1813,16 @@
   %7D%0A  %7D;
-%0A%7D;
 %0A%0Aexport
@@ -2040,29 +2040,28 @@
 S_INFO%5D.
-BaseComponent
+childFactory
 ,%0A    );
@@ -2102,16 +2102,21 @@
 Mappers(
+%0A    
 %5Bmapper%5D
@@ -2116,17 +2116,40 @@
 mapper%5D,
- 
+%0A    createEagerFactory(
 BaseComp
@@ -2153,16 +2153,21 @@
 omponent
+),%0A  
 );%0A%7D, 'm

create the child factory only once