import _ from 'lodash';
import PropTypes from 'prop-types';
import React, {Fragment, useEffect, useState} from 'react';
import {Field, Record} from '@airtable/blocks/models';
import {Box, Button, expandRecord} from '@airtable/blocks/ui';

import Flashcard from './Flashcard';

/**
 * Responsible for picking a random record from the given records.
 * Keeps track of removed records.
 */
export default function FlashcardContainer({records, settings}) {
    const [record, setRecord] = useState(_.sample(records));
    const [removedRecordsSet, setRemovedRecordsSet] = useState(new Set());
    const [shouldShowAnswer, setShouldShowAnswer] = useState(false);

    function handleRemoveRecord() {
        const newRemovedRecordsSet = new Set(removedRecordsSet);
        setRemovedRecordsSet(newRemovedRecordsSet.add(record));
        setShouldShowAnswer(false);
        handleNewRecord();
    }

    function handleNewRecord() {
        setRecord(_.sample(records.filter(r => r !== record && !removedRecordsSet.has(r))));
    }

    function reset() {
        setRemovedRecordsSet(new Set());
        // Can't use handleNewRecord here because setting state is async, so removedRecordsSet won't
        // be updated yet.
        setRecord(_.sample(records));
    }

    // Handle updating record and removedRecordsSet due to records changing
    useEffect(() => {
        const allRecordsSet = new Set(records);
        const newRemovedRecordsSet = new Set();
        for (const removedRecord of removedRecordsSet) {
            if (allRecordsSet.has(removedRecord)) {
                newRemovedRecordsSet.add(removedRecord);
            }
        }
        if (newRemovedRecordsSet.size !== removedRecordsSet.size) {
            setRemovedRecordsSet(newRemovedRecordsSet);
        }

        if (!allRecordsSet.has(record)) {
            handleNewRecord();
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [records]);

    let primaryButton;
    if (record) {
        if (shouldShowAnswer || !settings.answerField) {
            // Either already showing the answer, or there's no answer
            // field. So show the "Next" button to go to the next question.
            primaryButton = (
                <Button marginLeft={3} variant="primary" size="large" onClick={handleRemoveRecord}>
                    Next question
                </Button>
            );
        } else {
            primaryButton = (
                <Button
                    marginLeft={3}
                    variant="primary"
                    size="large"
                    onClick={() => setShouldShowAnswer(true)}
                >
                    Show answer
                </Button>
            );
        }
    } else {
        // No records left.
        primaryButton = (
            <Button marginLeft={3} variant="primary" size="large" icon="redo" onClick={reset}>
                Start over
            </Button>
        );
    }

    return (
        <Fragment>
            <Flashcard record={record} settings={settings} shouldShowAnswer={shouldShowAnswer} />
            <Box flex="none" borderTop="thick" display="flex" marginX={3} paddingY={3}>
                {record && (
                    <Button icon="expand" variant="secondary" onClick={() => expandRecord(record)}>
                        Expand record
                    </Button>
                )}
                <Box flexGrow={1} />
                {primaryButton}
            </Box>
        </Fragment>
    );
}

FlashcardContainer.propTypes = {
    records: PropTypes.arrayOf(PropTypes.instanceOf(Record)).isRequired,
    settings: PropTypes.shape({
        questionField: PropTypes.instanceOf(Field).isRequired,
        answerField: PropTypes.instanceOf(Field),
    }).isRequired,
};