import React from 'react';
import generateEntityId from 'utils/entities';
import Immutable from 'immutable';

let nextVersion = 0;

export default function connectService(service) {
  return (WrappedComponent) => {
    // Let's us keep track for hot reloading
    const version = nextVersion++;
    class ServiceConnect extends React.Component {
      constructor(props, context) {
        super(props, context);
        this.props = props;
        this.version = version;
        this.entityId = generateEntityId();
        // This seems to be the best place to do this right now...
        this.state = {
          serviceState: null
        };
        this.serviceChangeHandler = this.serviceChangeHandler.bind(this);
        this.subscribe();
      }
      componentWillReceiveProps(nextProps) {
        this.update(nextProps);
      }
      componentWillUnmount() {
        // Removes feed subscription and sets as dead for any stray updates
        this.dead = true;
        this.unsubscribe();
      }
      // Service methods
      update(props) {
        service.updateSubscriber(this.entityId, props, this.props, this.serviceChangeHandler);
      }
      subscribe() {
        this.initialServiceState = service.addSubscriber(this.entityId, this.props, this.serviceChangeHandler);
      }
      unsubscribe() {
        service.removeSubscriber(this.entityId, this.props);
      }
      serviceChangeHandler(state) {
        // Because we don't queue up all the unsubscribes we have to do this
        if (this.dead) {
          this.unsubscribe();
          return;
        }
        this.setState({
          serviceState: state
        });
      }
      computePassedState() {
        return Object.assign({service: service, entity: this.entityId}, this.initialServiceState, this.state.serviceState);
      }
      render() {
        const passedState = this.computePassedState();
        return (
          <WrappedComponent {...passedState} {...this.props} ref="wrapped" />
        );
      }
    }
    if (process.env.NODE_ENV !== 'production') {
      ServiceConnect.prototype.componentWillUpdate = function componentWillUpdate() {
        if (this.version === version) {
          return;
        }
        // We are hot reloading!
        this.version = version;
        // Update the bindings
        this.subscribe();
      };
    }
    return ServiceConnect;
  };
}
