import React, { Component } from 'react';
import { connect } from 'react-redux';

import {
	addComponent,
	removeComponent,
	watchComponent,
	updateQuery,
	setQueryOptions,
} from '@appbaseio/reactivecore/lib/actions';
import { pushToAndClause } from '@appbaseio/reactivecore/lib/utils/helper';
import types from '@appbaseio/reactivecore/lib/utils/types';

class ReactiveComponent extends Component {
	constructor(props) {
		super(props);

		this.internalComponent = null;

		let onQueryChange = null;
		if (props.onQueryChange) {
			onQueryChange = props.onQueryChange;
		}

		this.setQuery = (obj) => {
			this.props.updateQuery({
				...obj,
				componentId: props.componentId,
				label: props.filterLabel,
				showFilter: props.showFilter,
				onQueryChange,
				URLParams: props.URLParams,
			});
		};

		if (props.defaultQuery) {
			this.internalComponent = `${props.componentId}__internal`;
		}
	}

	componentWillMount() {
		this.props.addComponent(this.props.componentId);
		if (this.internalComponent) {
			this.props.addComponent(this.internalComponent);
		}

		this.setReact(this.props);

		// set query for internal component
		if (this.internalComponent && this.props.defaultQuery) {
			const { query, ...queryOptions } = this.props.defaultQuery;

			if (queryOptions) {
				this.props.setQueryOptions(this.internalComponent, queryOptions, false);
			}

			this.props.updateQuery({
				componentId: this.internalComponent,
				query: query || null,
			});
		}
	}

	componentWillUnmount() {
		this.props.removeComponent(this.props.componentId);

		if (this.internalComponent) {
			this.props.removeComponent(this.internalComponent);
		}
	}

	setReact = (props) => {
		const { react } = props;

		if (react) {
			if (this.internalComponent) {
				const newReact = pushToAndClause(react, this.internalComponent);
				props.watchComponent(props.componentId, newReact);
			} else {
				props.watchComponent(props.componentId, react);
			}
		} else if (this.internalComponent) {
			props.watchComponent(props.componentId, { and: this.internalComponent });
		}
	};

	render() {
		const {
			children,
			addComponent,
			watchComponent,
			removeComponent,
			setQueryOptions,
			updateQuery,
			...rest
		} = this.props;

		try {
			const childrenWithProps = React.Children.map(children, child =>
				React.cloneElement(child, { ...rest, setQuery: this.setQuery }));
			return <div>{childrenWithProps}</div>;
		} catch (e) {
			return null;
		}
	}
}

ReactiveComponent.defaultProps = {
	URLParams: false,
	showFilter: true,
};

ReactiveComponent.propTypes = {
	componentId: types.stringRequired,
	hits: types.data,
	aggregations: types.selectedValues,
	selectedValue: types.selectedValue,
	addComponent: types.funcRequired,
	removeComponent: types.funcRequired,
	watchComponent: types.funcRequired,
	updateQuery: types.funcRequired,
	setQueryOptions: types.funcRequired,
	onQueryChange: types.func,
	URLParams: types.boolRequired,
	showFilter: types.bool,
	filterLabel: types.string,
	defaultQuery: types.selectedValues,
	react: types.react,
	children: types.children,
};

const mapStateToProps = (state, props) => ({
	hits: state.hits[props.componentId] && state.hits[props.componentId].hits || [],
	aggregations: state.aggregations[props.componentId] && state.aggregations[props.componentId] || null,
	selectedValue: state.selectedValues[props.componentId] && state.selectedValues[props.componentId].value || null,
});

const mapDispatchtoProps = dispatch => ({
	addComponent: component => dispatch(addComponent(component)),
	removeComponent: component => dispatch(removeComponent(component)),
	watchComponent: (component, react) => dispatch(watchComponent(component, react)),
	updateQuery: updateQueryObject => dispatch(updateQuery(updateQueryObject)),
	setQueryOptions: (component, props, execute) => dispatch(setQueryOptions(component, props, execute)),
});

export default connect(mapStateToProps, mapDispatchtoProps)(ReactiveComponent);

@@ -2112,24 +2112,31 @@
 addComponent
+: addFn
 ,%0A%09%09%09watchCo
@@ -2138,24 +2138,33 @@
 tchComponent
+: watchFn
 ,%0A%09%09%09removeC
@@ -2167,24 +2167,34 @@
 oveComponent
+: removeFn
 ,%0A%09%09%09setQuer
@@ -2201,16 +2201,32 @@
 yOptions
+: queryOptionsFn
 ,%0A%09%09%09upd
@@ -2233,16 +2233,26 @@
 ateQuery
+: updateFn
 ,%0A%09%09%09...
@@ -3178,16 +3178,17 @@
 %0A%09hits: 
+(
 state.hi
@@ -3200,33 +3200,35 @@
 ops.componentId%5D
- 
+%0A%09%09
 && state.hits%5Bpr
@@ -3248,16 +3248,17 @@
 Id%5D.hits
+)
  %7C%7C %5B%5D,%0A
@@ -3272,16 +3272,17 @@
 ations: 
+(
 state.ag
@@ -3302,33 +3302,35 @@
 ops.componentId%5D
- 
+%0A%09%09
 && state.aggrega
@@ -3353,16 +3353,17 @@
 onentId%5D
+)
  %7C%7C null
@@ -3380,16 +3380,17 @@
 dValue: 
+(
 state.se
@@ -3420,17 +3420,19 @@
 onentId%5D
- 
+%0A%09%09
 && state
@@ -3471,16 +3471,17 @@
 d%5D.value
+)
  %7C%7C null
@@ -3895,16 +3895,19 @@
 Options(
+%0A%09%09
 componen
@@ -3908,31 +3908,38 @@
 mponent,
- 
+%0A%09%09
 props,
- 
+%0A%09%09
 execute
+,%0A%09
 )),%0A%7D);%0A

Fix linting in ReactiveComponent