import * as React from "react";

import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import TextField from "@material-ui/core/TextField";
import Grid from "@material-ui/core/Grid";
import Button from "@material-ui/core/Button";
import Typography from "@material-ui/core/Typography";
import Popover from "@material-ui/core/Popover";
import LinearProgress from "@material-ui/core/LinearProgress";
import CircularProgress from "@material-ui/core/CircularProgress";
import Paper from "@material-ui/core/Paper";

import { withRouter } from "react-router-dom";

import { IVocab, IReviewCard, vocabToReviewCard, reviewQTypeToStr } from "../models/vocab";
import { ReviewType, IReviewMetadata } from "../models/review";

import { levW } from "../algorithms/levenshtein";
import { LEVENSHTEIN_MAX_DISTANCE } from "../config";

import { Queue } from "../utils/queue";

interface IProps {
    levelId?: number;
    vocabByLevel?: (level: number) => Promise<IVocab[]>;
    vocabByQueue?: () => Promise<IVocab[]>;
    reviewType: ReviewType;

    history: any;

    loading: boolean;
    vocab: IVocab[];
    current: IReviewCard;
    popoverOpen: boolean;
    popoverText: string;
    popoverColor: string;
    popoverTextColor: string;

    setSummary: (state: boolean) => void;
    setPopover: (state: boolean, text: string, color: string, textColor: string) => void;
    drawerButtonState: (state: boolean) => void;
    setLastReview: (meta: IReviewMetadata) => void;
    setReview: (curent: IReviewCard, meta: IReviewMetadata) => void;
    setLoading: (state: boolean) => void;
}

const ReviewPageWithRouter = withRouter(
    class ReviewPage extends React.Component<IProps> {
        private vocab: IVocab[] = [];
        private reviewQueue: Queue<IReviewCard> = new Queue();
        // Used for positioning the popover
        private buttonRef: HTMLButtonElement;
        private inputRef: HTMLInputElement;
        private metadata: IReviewMetadata = { correct: 0, wrong: 0 };

        constructor(props: any) {
            super(props);

            // Hide the drawer button
            this.props.drawerButtonState(false);

            const vocToQueue = () => {
                this.vocab.forEach((vocab) => {
                    vocabToReviewCard(vocab).forEach(this.reviewQueue.enqueue);
                });
                this.props.setReview(this.reviewQueue.dequeue(), {
                    correct: 0,
                    wrong: 0,
                });
                this.props.setLoading(false);
            };

            // Get the correct vocabulary
            const { reviewType, vocabByLevel, levelId, vocabByQueue } = this.props;

            // Just to make TSC shut up
            const noopPromise = () => {
                return new Promise<IVocab[]>((res, rej) => {
                    rej([]);
                });
            };
            const vocabByLevelW = vocabByLevel || noopPromise;
            const vocabByQueueW = vocabByQueue || noopPromise;
            const getVocab = {
                [ReviewType.LEVEL]: () => vocabByLevelW(levelId),
                [ReviewType.QUEUE]: () => vocabByQueueW(),
            }[reviewType];

            getVocab().then((res: IVocab[]) => {
                this.vocab = res;
                vocToQueue();
            });
        }

        increaseMeta = (correct: number, wrong: number): IReviewMetadata => {
            const { metadata } = this;

            return {
                wrong: metadata.wrong + wrong,
                correct: metadata.correct + correct,
            };
        }

        vocabFromId = (id: number): IVocab | {} => {
            return this.vocab.find((el) => el.id === this.props.current.id);
        }

        checkInput = () => {
            // Check if the given answer is somewhere in the german words
            const input = this.inputRef.value || "";

            // Map all possible answers to lowercase ( => ignore casing)
            const answers = this.props.current.answers.map((el) => el.toLowerCase());
            // Calculate the distances to all possible answers
            const dists = answers.map((el) => levW(input.toLowerCase(), el));
            // Find the lowest distance
            const minDist = Math.min(...dists);

            console.log("Review Queue size:", this.reviewQueue.size());

            // Check if the user's answer was correct
            if (minDist === 0) {
                // TODO: Show it's correct?
                // Show the next vocab word
                if (this.reviewQueue.size() === 0) {
                    // Go to the summary screen
                    this.props.setLastReview(this.metadata);
                    this.props.setLoading(true);
                    this.props.history.push("/review/summary");
                } else {
                    // Increase the vocab
                    this.props.setReview(this.reviewQueue.dequeue(), this.increaseMeta(1, 0));
                    this.inputRef.value = "";
                }
            } else if (minDist <= LEVENSHTEIN_MAX_DISTANCE) {
                this.props.setPopover(true, "Das war fast richtig", "yellow", "black");
            } else {
                // Find the IVocab item
                const vocab = this.vocabFromId(this.props.current.id);
                if (vocab) {
                    // Re-Add the vocabulary item to the review queue
                    // TODO: Only re-add when it when it's not re-queued
                    // vocabToReviewCard(vocab).forEach(this.reviewQueue.enqueue);
                } else {
                    console.log("[ReviewPage::checkInput] Could not find IVocab item for wrong IReviewCard");
                }

                this.props.setPopover(true, "Das war nicht richtig", "red", "white");
            }

            // TODO(?): Show a snackbar for showing the updated score
        }

        render() {
            if (this.props.loading) {
                return <div>
                    <Grid
                        container
                        spacing={0}
                        direction="column"
                        alignItems="center"
                        justify="center"
                        style={{ minHeight: '100vh' }}>
                        <Grid item xs={12}>
                            <Paper className="paper">
                                <Grid container direction="column" spacing={8}>
                                    <CircularProgress />
                                </Grid>
                            </Paper>
                        </Grid>
                    </Grid>

                </div>;
            }


            const { question, qtype } = this.props.current;
            const questionTitle = `${question} (${reviewQTypeToStr(qtype)})`;
            // TODO:
            const progress = 50;

            return <div>
                <Grid container justify="center">
                    <Grid item style={{ width: "100%" }}>
                        <Card>
                            <CardContent>
                                <Grid container direction="column">
                                    <Typography variant="display2">
                                        {questionTitle}
                                    </Typography>
                                    <TextField
                                        margin="normal"
                                        fullWidth={true}
                                        inputRef={node => this.inputRef = node}
                                        onKeyPress={(ev) => {
                                            // Allow checking of the answer by pressing Enter
                                            if (ev.key === "Enter")
                                                this.checkInput();
                                        }} />
                                    <LinearProgress
                                        variant="determinate"
                                        value={progress} />
                                    <Popover
                                        open={this.props.popoverOpen}
                                        anchorOrigin={{
                                            vertical: "center",
                                            horizontal: "center"
                                        }}
                                        transformOrigin={{
                                            vertical: "bottom",
                                            horizontal: "center"
                                        }}
                                        anchorEl={this.buttonRef}
                                        onClose={() => this.props.setPopover(false, "", "", "")}
                                        PaperProps={{
                                            style: {
                                                backgroundColor: this.props.popoverColor,
                                                padding: 10,
                                                color: this.props.popoverTextColor,
                                            }
                                        }}>
                                        <Typography
                                            variant="button"
                                            color="inherit">
                                            {this.props.popoverText}
                                        </Typography>
                                    </Popover>
                                    <Button
                                        onClick={this.checkInput}
                                        buttonRef={node => this.buttonRef = node}>
                                        Prüfen
                                    </Button>
                                </Grid>
                            </CardContent>
                        </Card>
                    </Grid>
                </Grid>
            </div>;
        }
    }
);
export default ReviewPageWithRouter;
