import * as React from "react";

import { BrowserRouter, Route, Redirect } from "react-router-dom";

import AuthRoute from "../security/AuthRoute";
import { setSessionToken, removeSessionToken } from "../security/Token";

import Dashboard from "../pages/dashboard";
import LoginPage from "../containers/LoginPage";
import LevelListPage from "../containers/LevelList";
import LevelPage from "../containers/LevelPage";
import ReviewPage from "../containers/Review";
import SummaryPage from "../containers/SummaryPage";
import WelcomePage from "../pages/intro";

import Drawer from "../containers/Drawer";

import { BACKEND_URL } from "../config";

import { ILevel } from "../models/level";
import { ILearner } from "../models/learner";
import { IVocab, VocabType } from "../models/vocab";
import { IReviewMetadata, ReviewType } from "../models/review";
import { IUser } from "../models/user";

interface IProps {
    authenticated: boolean;

    setAuthenticated: (status: boolean) => void;
    setUser: (user: IUser) => void;
};

// TODO: Replace the sessionStorage with localStorage?
// TODO: Cache API-Calls
// TODO: When mounting without a login, check if the sessionToken is still valid
export default class Application extends React.Component<IProps> {
    getLevels(): Promise<ILevel[]> {
        console.log("STUB: Application::getLevels");

        return new Promise((res, rej) => {
            // TODO: Actually fetch them from somewhere
            setTimeout(() => {
                const levels = [{
                    name: "Der Bauer auf dem Feld",
                    desc: "So fängt alles an: Du bist ein einfacher Bauer und musst dich die Karriereleiter mit deinen freshen Latein-Skills hinaufarbeiten",
                    level: 1,
                    done: true,
                }, {
                    name: "???",
                    desc: "Warum schreibe ich überhaupt was?dsd dddddddddddddddddddddd",
                    level: 2,
                    done: false,
                }];

                res(levels);

            }, 2000);
        });
    }

    getLastReview = (): IReviewMetadata => {
        console.log("STUB: Application::getLastReview");

        // TODO: Actually fetch this
        // TODO: Stub
        return {} as IReviewMetadata;
    }

    setLastReview = (meta: IReviewMetadata) => {
        console.log("STUB: Application::setLastReview");

        // TODO: Send this to the server
        this.setState({
            lastReview: meta,
        });
    }

    getReviewQueue = (): Promise<IVocab[]> => {
        console.log("STUB: Application::getReviewQueue");

        // TODO: Implement
        return new Promise((res, rej) => {
            setTimeout(() => {
                res([
                    {
                        german: ["Wein"],
                        hint: "Worte auf '-um' sind meistens NeutrUM",
                        type: VocabType.NOMEN,
                        latin: {
                            grundform: "Vinum",
                            genitiv: "Vini",
                            genus: "Neutrum"
                        },
                        id: 0
                    }/* , {
                      *    latin: "Vici",
                      *    german: "<Wortbedeutung>",
                      *    hint: "Wird \"Viki\" und nicht \"Vichi\" ausgesprochen",
                      *    mnemonic: "Merk dir das Wort mit Caesars berühmten Worten: \"Veni Vidi Vici\"; Er kam, sah und siegte",
                      *    type: VocabType.NOMEN,
                      *    id: 2
                        }, {
                      *    latin: "fuga",
                      *    german: "Flucht",
                      *    hint: "Worte auf \"-a\" sind FeminA",
                      *    type: VocabType.NOMEN,
                      *    id: 3
                        } */
                ]);
            }, 2000);
        });
    }

    getLearners(): ILearner[] {
        console.log("STUB: Application::getLearners");

        // TODO: Implement
        return [{
            username: "Polynomdivision",
            level: 5,
            score: 400,
        }, {
            username: "Polynomdivision2",
            level: 3,
            score: 500,
        }, {
            username: "Der eine Typ",
            level: 7,
            score: 100,
        }];
    }

    getTopTenLearners(): ILearner[] {
        console.log("STUB: Application::getTopTenLearners");

        // TODO: Implement
        return [{
            username: "Polynomdivision",
            level: 5,
            score: 400,
        }, {
            username: "Polynomdivision2",
            level: 3,
            score: 500,
        }, {
            username: "Der eine Typ",
            level: 7,
            score: 100,
        }];
    }

    getNextLevel(): ILevel {
        console.log("STUB: Application::getNextLevel");

        // TODO: Actually fetch data
        return {
            name: "???",
            desc: "Warum schreibe ich überhaupt was?dsd dddddddddddddddddddddd",
            level: 2,
            done: false,
        };
    }

    getLevelVocab(id: number): Promise<IVocab[]> {
        console.log("STUB: Application::getLevelVocab");

        // TODO: Actually implement this
        return new Promise((res, rej) => {
            setTimeout(() => {
                res([{
                    german: ["Wein"],
                    hint: "Worte auf '-um' sind meistens NeutrUM",
                    type: VocabType.NOMEN,
                    latin: {
                        grundform: "Vinum",
                        genitiv: "Vini",
                        genus: "Neutrum"
                    },
                    id: 0
                }/* , {
                  *    latin: "Vici",
                  *    german: "<Wortbedeutung>",
                  *    hint: "Wird \"Viki\" und nicht \"Vichi\" ausgesprochen",
                  *    mnemonic: "Merk dir das Wort mit Caesars berühmten Worten: \"Veni Vidi Vici\"; Er kam, sah und siegte",
                  *    type: VocabType.NOMEN,
                  *    id: 2
                    }, {
                  *    latin: "fuga",
                  *    german: "Flucht",
                  *    hint: "Worte auf \"-a\" sind FeminA",
                  *    type: VocabType.NOMEN,
                  *    id: 3
                    } */]);
            }, 2000);
        });
    }

    login = (username: string, password: string): Promise<IUser | {}> => {
        return new Promise((res, rej) => {
            fetch(`${BACKEND_URL}/login`, {
                method: "POST",
                headers: new Headers({
                    "Content-Type": "application/json",
                }),
                body: JSON.stringify({
                    // NOTE: We will force HTTPS, so this should not be a
                    // problem
                    username,
                    password,
                }),
            }).then(data => data.json())
                .then(resp => {
                    if (resp.error === "0") {
                        // Successful login
                        this.props.setUser(resp.data);
                        setSessionToken(window, resp.data.sessionToken);

                        res(resp.data);
                    } else {
                        rej({});
                    }
                });
        });
    }

    logout = () => {
        // TODO: Tell the server that we're logging ourselves out
        removeSessionToken(window);
        this.props.setAuthenticated(false);
    }

    // Checks whether the user is logged in
    isAuthenticated = () => {
        // TODO: Security?
        // TODO: Implement
        return this.props.authenticated;
    }

    render() {
        // TODO: Show a spinner before mounting the routes, so that we can
        //       check if were authenticated before doing any requests
        return <BrowserRouter
            basename="/app/">
            <div className="flex" >
                <Drawer logout={this.logout} />
                <div className="content">
                    <Route exact path="/" component={() => <Redirect to="/login" />} />
                    <Route exact path="/login" component={() => {
                        return <LoginPage login={this.login} />
                    }} />
                    <AuthRoute
                        isAuth={this.isAuthenticated}
                        path="/dashboard"
                        component={() => {
                            return <Dashboard
                                nextLevel={this.getNextLevel}
                                getLastReview={this.getLastReview}
                                getTopTen={this.getTopTenLearners} />
                        }} />
                    <AuthRoute
                        isAuth={this.isAuthenticated}
                        path="/welcome"
                        component={() => {
                            return <WelcomePage />
                        }} />
                    <AuthRoute
                        isAuth={this.isAuthenticated}
                        path="/levelList"
                        component={() => <LevelListPage
                            getLevels={this.getLevels} />} />
                    {/*We cannot use AuthRoute here, because match is undefined otherwise*/}
                    <Route
                        path="/level/:id"
                        component={({ match }) => {
                            if (this.isAuthenticated()) {
                                return <LevelPage
                                    id={match.params.id}
                                    levelVocab={this.getLevelVocab}
                                    drawerButtonState={this.drawerButtonState}
                                    setLastReview={this.setLastReview} />;
                            } else {
                                return <Redirect to="/login" />;
                            }
                        }} />
                    <Route
                        path="/review/level/:id"
                        component={({ match }) => {
                            if (this.isAuthenticated()) {
                                return <ReviewPage
                                    reviewType={ReviewType.LEVEL}
                                    levelId={match.params.id}
                                    vocabByLevel={this.getLevelVocab}
                                    setLastReview={this.setLastReview} />;
                            } else {
                                return <Redirect to="/login" />;
                            }
                        }} />
                    <AuthRoute
                        isAuth={this.isAuthenticated}
                        path="/review/queue"
                        component={() => {
                            return <ReviewPage
                                reviewType={ReviewType.QUEUE}
                                vocabByQueue={this.getReviewQueue}
                                drawerButtonState={this.drawerButtonState}
                                setLastReview={this.setLastReview} />;
                        }} />
                    <AuthRoute
                        isAuth={this.isAuthenticated}
                        path="/review/summary"
                        component={() => {
                            return <SummaryPage />
                        }} />
                </div>
            </div >
        </BrowserRouter >;
    }
};
