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 { Redirect } 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) => IVocab[];
    vocabByQueue?: () => IVocab[];

    setLastReview: (meta: IReviewMetadata) => void;

    reviewType: ReviewType;

    drawerButtonState: (state: boolean) => void;
}

interface IState {
    input: string;
    current: IReviewCard;

    metadata: IReviewMetadata;

    toSummary: boolean;

    popoverOpen: boolean;
    popoverText: string;
    popoverColor: string;
}

export default class ReviewPage extends React.Component<IProps, IState> {
    private vocab: IVocab[] = [];
    private reviewQueue: Queue<IReviewCard> = undefined;
    // Used for positioning the popover
    private buttonRef: HTMLButtonElement;

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

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

        // Get the correct vocabulary
        const { reviewType, vocabByLevel, levelId, vocabByQueue } = this.props;
        switch (reviewType) {
            case ReviewType.LEVEL:
                if (!vocabByLevel || !levelId) {
                    alert("[ReviewPage::constructor] vocabByLevel or levelId undefined");
                } else {
                    this.vocab = vocabByLevel(levelId);
                }

                break;
            case ReviewType.QUEUE:
                if (!vocabByQueue) {
                    alert("[ReviewPage::constructor] vocabByQueue undefined");
                } else {
                    this.vocab = vocabByQueue();
                }

                break;
        }

        // Turn the vocabulary into IReviewCards and queue them
        if (!this.reviewQueue) {
            this.reviewQueue = new Queue();
            this.vocab.forEach((vocab) => {
                vocabToReviewCard(vocab).forEach(this.reviewQueue.enqueue);
            });
        }

        this.state = {
            input: "",
            current: this.reviewQueue.dequeue(),
            metadata: {
                correct: 0,
                wrong: 0,
            },

            toSummary: false,

            popoverOpen: false,
            popoverText: "",
            popoverColor: "red",
        };
    }

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

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

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

    checkInput = () => {
        // Check if the given answer is somewhere in the german words
        const { input } = this.state;

        // Map all possible answers to lowercase ( => ignore casing)
        const answers = this.state.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(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.setState({
                    toSummary: true,
                }, () => {
                    // Update the "Last Review" data
                    this.props.setLastReview(this.state.metadata);
                });
            } else {
                // Increase the vocab
                this.setState({
                    current: this.reviewQueue.dequeue(),
                    input: "",
                    // Add one correct answer
                    metadata: this.increaseMeta(1, 0),
                });
            }
        } else if (minDist <= LEVENSHTEIN_MAX_DISTANCE) {
            // TODO: Show a hint
            console.log("Partially correct");
        } else {
            // Find the IVocab item
            const vocab = this.vocabFromId(this.state.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.setState({
                popoverOpen: true,
                popoverText: "Das war nicht richtig",
                popoverColor: "red",
                // TODO: Or maybe don't reset the text
                input: "",
                metadata: this.increaseMeta(0, 1),
            });
        }

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

    render() {
        const { question, qtype } = this.state.current;
        const questionTitle = `${question} (${reviewQTypeToStr(qtype)})`;

        return <div>
            {
                this.state.toSummary ? (
                    <Redirect to="/review/summary" />
                ) : undefined
            }
            <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}
                                    value={this.state.input}
                                    onChange={(ev) => this.setState({
                                        input: ev.target.value,
                                    })}
                                    onKeyPress={(ev) => {
                                        // Allow checking of the answer by pressing Enter
                                        if (ev.key === "Enter")
                                            this.checkInput();
                                    }} />
                                <Popover
                                    open={this.state.popoverOpen}
                                    anchorOrigin={{
                                        vertical: "center",
                                        horizontal: "center"
                                    }}
                                    transformOrigin={{
                                        vertical: "bottom",
                                        horizontal: "center"
                                    }}
                                    anchorEl={this.buttonRef}
                                    onClose={() => this.setState({
                                        popoverOpen: false,
                                    })}
                                    PaperProps={{
                                        style: {
                                            backgroundColor: this.state.popoverColor,
                                            padding: 10,
                                            color: "white"
                                        }
                                    }}>
                                    <Typography
                                        variant="button"
                                        color="inherit">
                                        {this.state.popoverText}
                                    </Typography>
                                </Popover>
                                <Button
                                    onClick={this.checkInput}
                                    buttonRef={node => this.buttonRef = node}>
                                    Prüfen
                            </Button>
                            </Grid>
                        </CardContent>
                    </Card>
                </Grid>
            </Grid>
        </div>;
    }
};
