import React from 'react';
import PropTypes from 'prop-types';
import {Provider} from 'react-redux';
import {createStore, applyMiddleware, compose} from 'redux';
import throttle from 'redux-throttle';

import {intlShape} from 'react-intl';
import {IntlProvider, updateIntl} from 'react-intl-redux';
import {intlInitialState} from '../reducers/intl.js';
import {initialState as modeInitialState, setPlayer, setFullScreen} from '../reducers/mode.js';
import reducer from '../reducers/gui';
import ErrorBoundary from '../containers/error-boundary.jsx';

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const enhancer = composeEnhancers(
    applyMiddleware(
        throttle(300, {leading: true, trailing: true})
    )
);

/*
 * Higher Order Component to provide redux state. If an `intl` prop is provided
 * it will override the internal `intl` redux state
 * @param {React.Component} WrappedComponent - component to provide state for
 * @returns {React.Component} component with redux and intl state provided
 */
const AppStateHOC = function (WrappedComponent) {
    class AppStateWrapper extends React.Component {
        constructor (props) {
            super(props);
            let intl = {};
            let mode = {};
            if (props.intl) {
                intl = {
                    defaultLocale: 'en',
                    locale: props.intl.locale,
                    messages: props.intl.messages
                };
            } else {
                intl = intlInitialState.intl;
            }
            if (props.isPlayerOnly || props.isFullScreen) {
                mode = {
                    isFullScreen: props.isFullScreen || false,
                    isPlayerOnly: props.isPlayerOnly || false
                };
            } else {
                mode = modeInitialState;
            }

            this.store = createStore(
                reducer,
                {
                    intl: intl,
                    mode: mode
                },
                enhancer);
        }
        componentDidUpdate (prevProps) {
            if (prevProps.intl !== this.props.intl) {
                this.store.dispatch(updateIntl(this.props.intl));
            }
            if (prevProps.isPlayerOnly !== this.props.isPlayerOnly) {
                this.store.dispatch(setPlayer(this.props.isPlayerOnly));
            }
            if (prevProps.isFullScreen !== this.props.isFullScreen) {
                this.store.dispatch(setFullScreen(this.props.isFullScreen));
            }
        }
        render () {
            return (
                <Provider store={this.store}>
                    <IntlProvider>
                        <ErrorBoundary action="Top Level App">
                            <WrappedComponent {...this.props} />
                        </ErrorBoundary>
                    </IntlProvider>
                </Provider>
            );
        }
    }
    AppStateWrapper.propTypes = {
        intl: intlShape,
        isFullScreen: PropTypes.bool,
        isPlayerOnly: PropTypes.bool
    };
    return AppStateWrapper;
};

export default AppStateHOC;