// @flow

import * as React from "react";
import PropTypes from "prop-types";
import hoistStatics from "hoist-non-react-statics";

import { getDisplayName } from "./utils";
import mapValues from "./shared/mapValues";
import { encode } from "./shared/QueryString";

type props = Object;

export default function withPhenomicApi<P>(
  ComposedComponent: React.ComponentType<P>,
  getQueries: (props: Object) => Object = () => ({})
) {
  const socketServerURL =
    // $FlowFixMe yeah yeah
    "http://localhost:" + process.env.PHENOMIC_SOCKET_PORT;
  const displayName = getDisplayName(ComposedComponent);

  class PhenomicContainerWithApi extends React.Component<props, void> {
    unsubscribe: Function | null;
    queries: Object;

    static getQueries = getQueries;
    static contextTypes = {
      query: PropTypes.func,
      phenomic: PropTypes.object,
      __prerendering: PropTypes.bool
    };

    static displayName = `withPhenomicApi(${displayName})`;

    constructor(props: props, context: Object) {
      super(props, context);
      this.computeQueries(props);
      // if we're on the server, let's just run the query
      if (this.context.__prerendering) {
        this.query();
      }
    }

    componentDidMount() {
      if (!this.context.__prerendering) {
        this.query();
      }
      this.unsubscribe = this.context.phenomic.subscribe(() => this.update());
      if (process.env.NODE_ENV !== "production") {
        require("socket.io-client")(socketServerURL).on(
          "change",
          this.forceQuery
        );
      }
    }

    componentWillReceiveProps(props: props) {
      this.computeQueries(props);
      this.schedule(() => this.query());
    }

    componentWillUnmount() {
      if (typeof this.unsubscribe === "function") {
        this.unsubscribe();
      }
      this.unsubscribe = null;

      if (process.env.NODE_ENV !== "production") {
        require("socket.io-client")(socketServerURL).removeListener(
          "change",
          this.forceQuery
        );
      }
    }

    forceQuery = () => {
      this.query(true);
    };
    update = () => {
      this.schedule(() => this.forceUpdate());
    };
    schedule = (func: Function) => {
      requestAnimationFrame(() => {
        if (typeof this.unsubscribe === "function") {
          func();
        }
      });
    };
    computeQueries = (props: props) => {
      this.queries = mapValues(getQueries(props), encode);
    };
    query = (force: boolean = false) => {
      const store = this.context.phenomic;
      const values = Object.keys(this.queries).map(key => this.queries[key]);
      if (force) {
        this.context.query(values);
      } else {
        this.context.query(
          values.filter(item => store.get(item).status !== "idle")
        );
      }
    };
    render() {
      const store = this.context.phenomic;
      const values = Object.keys(this.queries).map(key => this.queries[key]);
      const isLoading = values.some(item => !store.get(item).node);
      const hasErrored = values.some(
        item => store.get(item).status === "error"
      );
      const props = mapValues(this.queries, (value, key) =>
        store.get(this.queries[key])
      );
      if (hasErrored) {
        console.error(
          "An item is in error state",
          values.find(item => store.get(item).status === "error")
        );
        return (
          <ComposedComponent
            {...this.props}
            queries={getQueries(this.props)}
            hasError
            {...props}
          />
        );
      }
      return (
        <ComposedComponent
          {...this.props}
          queries={getQueries(this.props)}
          isLoading={isLoading}
          {...props}
        />
      );
    }
  }

  // $FlowFixMe I am lazy and "it works on my computer"
  return hoistStatics(PhenomicContainerWithApi, ComposedComponent);
}

@@ -3383,28 +3383,16 @@
  return 
-(%0A          
 %3CCompose
@@ -3401,28 +3401,16 @@
 omponent
-%0A           
  %7B...thi
@@ -3421,120 +3421,31 @@
 ops%7D
-%0A            queries=%7BgetQueries(this.props)%7D%0A            hasError%0A            %7B...props%7D%0A          /%3E%0A        )
+ hasError %7B...props%7D /%3E
 ;%0A  
@@ -3491,26 +3491,16 @@
 omponent
-%0A         
  %7B...thi
@@ -3511,61 +3511,8 @@
 ops%7D
-%0A          queries=%7BgetQueries(this.props)%7D%0A         
  isL
@@ -3529,26 +3529,16 @@
 Loading%7D
-%0A         
  %7B...pro
@@ -3540,24 +3540,16 @@
 ..props%7D
-%0A       
  /%3E%0A    

Revert "✨`@phenomic/plugin-renderer-react`: pass queries to component (in case of dynamic queries based on props, it can be handy to get those directly)"