import React, {ReactNode} from "react";
import {Error} from "../components/Error";
import {Route, RouteComponentProps, Switch, withRouter} from "react-router";
import {createApiRequestStore} from "../api/ApiRequestStore";
import MainPage from "../components/mainPage/MainPage";
import createMuiTheme from "@material-ui/core/styles/createMuiTheme";
import {ThemeProvider} from "@material-ui/core/styles";
import lightBlue from "@material-ui/core/colors/lightBlue";
import amber from "@material-ui/core/colors/amber";
import {PrivateRoute} from "../common/PrivateRoute";
import {AppRoutes, appRoutes} from "../common/appRoutes";
import {NotFound} from "../components/NotFound";
import {UserSummary} from "../api/RequestBodyData";
import Loader from "../common/Loader";
import Login from "../components/Login";
import {ErrorDialogData} from "../common/errorHandling/ErrorMapper";
import ErrorDialog from "../common/errorHandling/ErrorDialog";

const myTheme = createMuiTheme({
    palette: {
        primary: {
            main: lightBlue[200]
        },
        secondary: {
            main: amber[500]
        }
    }
});


type PathProps = {
    /* ... these are the properties that will come from the route that sent you to this component ... */
}

type NonRouterProps = {
    /* ... the properties that you expect to get explicitly ... */
}

type AppProps = NonRouterProps & RouteComponentProps<PathProps>

type AppState = {
    isAuthenticated: boolean,
    isLoading: boolean,
    isError: boolean,
    currentUser: UserSummary,
    errorDialogOpen: boolean,
    errorDialogData?: ErrorDialogData,
}


class App extends React.Component<AppProps, AppState> {
    private readonly requestStore = createApiRequestStore();
    private readonly appRoutes = appRoutes;


    readonly state: AppState = {
        isAuthenticated: false,
        isLoading: false,
        isError: false,
        currentUser: {} as UserSummary,
        errorDialogData: undefined,
        errorDialogOpen: false
    };

    private handleErrorDialogOpen = (dialogData: ErrorDialogData) => {
        this.setState({
            ...this.state,
            errorDialogOpen: true,
            errorDialogData: dialogData
        })
    };

    private handleErrorDialogClose = () => {
        this.setState({
            ...this.state,
            errorDialogOpen: false
        })
    };

    loadCurrentUser = () => {
        this.setState({isLoading: true});
        this.requestStore.getCurrentUser()
            .then(response => {
                this.setState({
                    currentUser: response,
                    isAuthenticated: true,
                    isLoading: false
                })
            }).catch(error => {
            this.setState({
                isLoading: false
            })
        })
    };


    handleContent = (getLoader: () => ReactNode, getContent: () => ReactNode): ReactNode => {
        if (this.state.isError) {
            return this.renderErrorPage()
        } else if (this.state.isLoading) {
            return getLoader()
        } else return getContent()
    };

    handleLogin = () => {
        this.loadCurrentUser();
        this.props.history.push(appRoutes.get(AppRoutes.MySite)!.siteUrl)
    };

    handleLogout = () => {
        this.setState({...this.state, isAuthenticated: false});
        this.props.history.push(appRoutes.get(AppRoutes.Login)!.siteUrl);
    };

    renderLoader = () => <Loader/>;

    renderContent = () => {
        return (
            <ThemeProvider theme={myTheme}>
                {(this.state.errorDialogOpen && this.state.errorDialogData) ?
                    <ErrorDialog data={this.state.errorDialogData} handleClose={this.handleErrorDialogClose}
                                 isOpen={this.state.errorDialogOpen}/> : undefined}
                <Switch>
                    <Route path={this.appRoutes.get(AppRoutes.Login)!.siteUrl}
                           render={(props => <Login
                               onLogin={this.handleLogin}
                               handleErrorDialogOpen={this.handleErrorDialogOpen}
                               handleErrorDialogClose={this.handleErrorDialogClose}
                               {...props}/>)}/>
                    <PrivateRoute isAuthenticated={this.state.isAuthenticated} path={"/"}
                                  render={(props => <MainPage currentUser={this.state.currentUser}
                                                              isAuthenticated={this.state.isAuthenticated}
                                                              appRoutes={this.appRoutes}
                                                              handleErrorDialogOpen={this.handleErrorDialogOpen}
                                                              handleErrorDialogClose={this.handleErrorDialogClose}
                                                              handleLogout={this.handleLogout}
                                                              {...props}/>)}/>
                    <Route component={NotFound}/>
                </Switch>
            </ThemeProvider>
        )
    };

    renderErrorPage = () => <Error/>;
    redirectToLogin = () => {
        this.props.history.push("/login")
    };


    render(): ReactNode {
        return this.handleContent(this.renderLoader, this.renderContent)
    }
}

export default withRouter(App)
