import React from 'react';
import {
    Switch,
    BrowserRouter,
    Route,
    Redirect
} from 'react-router-dom';

import {jss, JssProvider} from 'react-jss';

import {I18nProvider} from './lib/i18n';

import GlobalStyle from './style/GlobalStyle';

import {ThemeProvider, initialStyle, initialTheme, initMagnification, changeStyle, themeSwitcher} from './lib/theme';

import './style/font.scss';

import {addApi} from './lib/ApiRequest';

import FactoryPage from './layout/FactoryPage';
import FactoryControlPanel from './layout/FactoryControlPanel';

import {BackendProvider} from './feature/BackendConnect';
import {AuthProvider} from "./feature/Auth";
import {BrandingProvider} from "./component/Branding";
import {RoutesStoreProvider, withRoutesStore} from "./component/RoutesStore";
import {FeatureManagerProvider} from "./component/FeatureManager";
import {AuthPermissionProvider} from "./feature/AuthPermission";
import {ApiControlProvider} from "./component/ApiControl";
import {ErrorControlProvider} from "./component/ErrorControl";
import {MessagesContainer as ErrorMessageContainer} from "./component/ErrorMessages/MessagesContainer";
import {PusherProvider} from "./component/Pusher/Pusher";
import {StoreMediaProvider} from "./feature/Media/Stores/Media";
import {StoreUploadProvider} from "./feature/Media/Stores/Upload";

const localeConfig = {
    allLanguages: [
        "en",
        "de"
    ],
    defaultLanguage: "en",
    expirationTime: process.env.NODE_ENV === 'production' ? 2 * 24 * 60 * 60 * 1000 : 100,
    debug: false
};

class BaseRoute extends React.Component {

    render() {
        const {routes_page, routes_control_panel} = this.props;

        /**
         * Where no backendConnect or authPermission loading must be displayed before children are displayed
         * @type {string[]}
         */
        const except = ['auth', 'info'];

        return (
            <React.Fragment>
                <Switch>
                    <Route exact path="/:lng" render={(props) => (
                        false ? (
                            <Redirect to={'/' + props.match.params.lng + '/dashboard'}/>
                        ) : (
                            <Redirect to={'/' + props.match.params.lng + '/auth'}/>
                        )
                    )}/>

                    <Route path="/:lng" render={(props) => (
                        <BackendProvider except={except}>
                            <AuthProvider>
                                <AuthPermissionProvider except={except}>
                                    <PusherProvider>
                                        <StoreMediaProvider>
                                            <StoreUploadProvider>
                                                <Route path={routes_page.main} render={props => (
                                                    <FactoryPage routes={routes_page.routes}/>
                                                )}/>

                                                <Route path={routes_control_panel.main} render={props => (
                                                    <FactoryControlPanel routes={routes_control_panel.routes}/>
                                                )}/>

                                                {this.props.children}
                                            </StoreUploadProvider>
                                        </StoreMediaProvider>
                                    </PusherProvider>
                                </AuthPermissionProvider>
                            </AuthProvider>
                        </BackendProvider>
                    )}/>
                </Switch>
            </React.Fragment>
        );
    }
}

const Routing = withRoutesStore(BaseRoute);

/**
 * Bootstrap a React Application with a lot of default functionality
 */
class BaseApp extends React.Component {

    state = {
        theme: initialTheme,
        style: initialStyle,
        loading: false,
    };

    constructor(props) {
        super(props);
        themeSwitcher.provide(this.changeStyle);

        for(let api_name in this.props.api) {
            if(this.props.api.hasOwnProperty(api_name)) {
                addApi(api_name, this.props.api[api_name]);
            }
        }
    }

    componentDidMount() {
        initMagnification();
    }

    changeStyle = () => {
        let new_style = changeStyle(this.state.theme);

        if(new_style) {
            this.setState(new_style);
        } else {
            // todo: when current theme transition doesn't exist currently fails silently for user - only log within changeStyle
        }
    };

    render() {
        const {
            locales, routesComponents, branding, features
        } = this.props;

        const {style} = this.state;

        return (
            <JssProvider jss={jss}>
                <ThemeProvider theme={style}>
                    <React.Fragment>
                        <GlobalStyle/>

                        <ErrorControlProvider>
                            <BrandingProvider branding={branding}>
                                <BrowserRouter basename="/">
                                    <I18nProvider locales={locales} config={localeConfig}>
                                        <FeatureManagerProvider features={features}>
                                            <ApiControlProvider>
                                                <RoutesStoreProvider routesComponents={routesComponents}>
                                                    <Routing>
                                                        {this.props.children}
                                                    </Routing>
                                                </RoutesStoreProvider>

                                                <ErrorMessageContainer/>
                                            </ApiControlProvider>
                                        </FeatureManagerProvider>
                                    </I18nProvider>
                                </BrowserRouter>
                            </BrandingProvider>
                        </ErrorControlProvider>
                    </React.Fragment>
                </ThemeProvider>
            </JssProvider>
        );
    }
}

export default BaseApp;
