import React from 'react';
import {addHeader, ApiRequest, GET} from '../lib/ApiRequest';
import {withApiControl} from "../component/ApiControl";
import {withNamespaces} from 'react-i18next';

import {arrayFirst, isUndefined} from '@formanta/js';
import {withContextConsumer} from "@formanta/react";

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

import Loading from "../component/Loading";
import {withTheme} from "../lib/theme";
import {withBranding} from "../component/Branding";
import {ErrorBoundary} from "../component/ErrorBoundary";
import {withFeatureManager} from "../component/FeatureManager";

const BackendContext = React.createContext({});

class BackendProviderBase extends React.Component {
    constructor(props) {
        super(props);

        this.switchHook = (new_hook) => {
            if(this.state.hooks[new_hook]) {
                addHeader('CONTEXT_HOOK', this.state.hooks[new_hook].id);
                this.setState({hook_active: this.state.hooks[new_hook]});
                return true;
            } else {
                console.error('Hook switched to is not defined');
                return false;
            }
        };

        this.state = {
            connecting: false,
            hook_active: false,
            hooks_qty: 0,
            hooks: {},
            config: {},
            switchHook: this.switchHook,
        };
    }

    connectBackend(state_updater) {
        return new Promise((resolve, reject) => {
            if(true === this.state.connecting) {
                resolve(true);
            }

            state_updater('progress');
            (new ApiRequest('api', GET, 'backend'))
                .debug(true)
                .exec()
                .then((res) => {
                    if(res && res.data) {
                        resolve(res.data);
                    } else {
                        state_updater('error-data');
                        reject(false);
                    }
                })
                .catch((err) => {
                    state_updater('error');

                    this.props.handleApiFail(err, 'Backend Connect');
                });
        });
    };

    async componentDidMount() {
        const {isEnabled} = this.props;
        if(!isEnabled('backendConnect')) {
            return;
        }

        this.setState({connecting: this.state.connecting});
        this.connectBackend((state) => {
            this.setState({connecting: state});
        }).then(result => {
            if(result) {
                // using only named values on the top level
                if(result.hooks) {
                    if(Array.isArray(result.hooks)) {
                        let hook_first = arrayFirst(result.hooks);
                        let hooks = {};
                        let hooks_qty = 0;
                        result.hooks.forEach(hook => {
                            if(hook.id && hook.label) {
                                hooks[hook.id] = hook;
                                hooks_qty++;
                            } else {
                                if(isUndefined(hook.id) && isUndefined(hook.label)) {
                                    console.warn('Invalid Hook submitted, missing `id` and `label`:');
                                    console.warn(hook);
                                } else if(isUndefined(hook.id)) {
                                    console.warn('Invalid Hook submitted, missing `id`:');
                                    console.warn(hook);
                                } else if(isUndefined(hook.label)) {
                                    console.warn('Invalid Hook submitted, missing `label`:');
                                    console.warn(hook);
                                }
                            }
                        });

                        addHeader('CONTEXT_HOOK', hook_first.id);

                        this.setState({
                            hook_active: hook_first,
                            hooks_qty,
                            hooks,
                        });
                    } else {
                        console.warn('BackendConnector received invalid hooks');
                    }
                } else {
                    console.warn('BackendConnector received no hooks');
                }

                if(result.config) {
                    this.setState({config: result.config});
                }

                this.setState({connecting: true});
            } else {
                this.setState({connecting: false});
            }
        });
    }

    render() {
        const {
            theme, t,
            branding,
            isEnabled,
            except
        } = this.props;

        let exception = false;
        if(!isUndefined(except)) {
            exception = except.join('|');
        }

        const enabled = isEnabled('backendConnect');

        return (
            <BackendContext.Provider value={this.state}>
                {enabled ?
                    <Switch>
                        <Route exact path="/:lng" render={(props) => (
                            null
                        )}/>

                        {exception ?
                            <Route exact path={'/:lng/(' + exception + ')'} render={(props) => (
                                <ErrorBoundary>
                                    {this.props.children}
                                </ErrorBoundary>
                            )}/>
                            : null}

                        <Route path="/:lng" render={(props) => (
                            <ErrorBoundary>
                                {(true === this.state.connecting) ?
                                    this.props.children :
                                    <Loading name='App' errorWarning={'error' === this.state.connecting}>
                                        <div style={{textAlign: 'center'}}>
                                            {
                                                'dark' === theme.name && branding.logo.white ?
                                                    <branding.logo.white className={props.className}
                                                                         style={{width: '64px', height: '64px',}}/> :
                                                    <branding.logo.normal className={props.className}
                                                                          style={{width: '64px', height: '64px',}}/>
                                            }
                                            {'error' === this.state.connecting ?
                                                <p>{t('backend-connect.error')}</p> :
                                                'error-data' === this.state.connecting ?
                                                    <p>{t('backend-connect.error-data')}</p> :
                                                    <p>{t('backend-connect.connecting')} ...</p>}
                                        </div>
                                    </Loading>}
                            </ErrorBoundary>
                        )}/>
                    </Switch> :
                    this.props.children}
            </BackendContext.Provider>
        );
    }
}

const withBackend = withContextConsumer(BackendContext.Consumer);

const BackendProvider = withFeatureManager(withNamespaces('common')(withApiControl(withBranding(withTheme(BackendProviderBase)))));

export {BackendProvider, withBackend};