/* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable jsx-a11y/click-events-have-key-events */
/* eslint-disable react/jsx-props-no-spreading */
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { StopEvent, returnFalse, returnOne, returnTrue, returnZero } from '../../../ClientUtils';
import { emptyFunction } from '../../../Utils';
import { Doc, Opt } from '../../../fields/Doc';
import { DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { DocumentType } from '../../documents/DocumentTypes';
import { DragManager } from '../../util/DragManager';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
import { StyleProp } from '../StyleProp';
import { DocumentView } from '../nodes/DocumentView';
import { FieldViewProps } from '../nodes/FieldView';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import './CollectionCarouselView.scss';
import { CollectionSubView } from './CollectionSubView';
import { Tooltip } from '@mui/material';

enum cardMode {
    // PRACTICE = 'practice',
    STAR = 'star',
    // QUIZ = 'quiz',
    ALL = 'all',
}
enum practiceMode {
    PRACTICE = 'practice',
    QUIZ = 'quiz',
    NORMAL = 'normal',
}
enum practiceVal {
    MISSED = 'missed',
    CORRECT = 'correct',
}
@observer
export class CollectionCarouselView extends CollectionSubView() {
    private _dropDisposer?: DragManager.DragDropDisposer;
    @observable private _practiceMessage: string | undefined;
    @observable private _filterMessage: string | undefined;
    get practiceField() { return this.fieldKey + "_practice"; } // prettier-ignore
    get sideField() { return "_" + this.fieldKey + "_usePath"; } // prettier-ignore
    get starField()     { return this.fieldKey + "_star"; } // prettier-ignore

    constructor(props: any) {
        super(props);
        makeObservable(this);
        this.layoutDoc.filterOp = cardMode.ALL;
        this.layoutDoc.practiceMode = practiceMode.NORMAL;
        this.layoutDoc._carousel_index = 0;
    }

    componentWillUnmount() {
        this._dropDisposer?.();
    }

    protected createDashEventsTarget = (ele: HTMLDivElement | null) => {
        this._dropDisposer?.();
        if (ele) {
            this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
        }
    };

    @computed get carouselItems() {
        return this.childLayoutPairs.filter(pair => pair.layout.type !== DocumentType.LINK);
    }
    @computed get marginX() {
        return NumCast(this.layoutDoc.caption_xMargin, 50);
    }

    @action setPracticeMessage = (mes: string | undefined) => {
        this._practiceMessage = mes;
    };
    @action setFilterMessage = (mes: string | undefined) => {
        this._filterMessage = mes;
    };

    move = (dir: number) => {
        const moveToCardWithField = (match: (doc: Doc) => boolean): boolean => {
            let startInd = (NumCast(this.layoutDoc._carousel_index) + dir) % this.carouselItems.length;
            while (!match(this.carouselItems?.[startInd].layout) && (startInd + this.carouselItems.length) % this.carouselItems.length !== this.layoutDoc._carousel_index) {
                startInd = (startInd + dir + this.carouselItems.length) % this.carouselItems.length;
            }
            if (match(this.carouselItems?.[startInd].layout)) {
                this.layoutDoc._carousel_index = startInd;
                return true;
            }
            return match(this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)].layout);
        };

        switch (this.layoutDoc.practiceMode && this.layoutDoc.filterOp) {
            case practiceMode.PRACTICE && cardMode.ALL:
                if (!moveToCardWithField((doc: Doc) => doc[this.practiceField] !== practiceVal.CORRECT)) {
                    this._practiceMessage = 'Finished! Unselect practice mode to view all flashcards.';
                    this.carouselItems.forEach(item => { item.layout[this.practiceField] = undefined}); //prettier-ignore
                }
                break;
            case !practiceMode.PRACTICE && cardMode.STAR:
                if (!moveToCardWithField((doc: Doc) => !!doc[this.starField])) {
                    this._filterMessage = 'No starred items. Unselect this view to see all flashcards and star them.';
                }
                break;
            case practiceMode.PRACTICE && cardMode.STAR:
                if (!moveToCardWithField((doc: Doc) => doc[this.practiceField] !== practiceVal.CORRECT && doc[this.starField] === true)) {
                    this._filterMessage = 'No flashcards to show! Unselect star mode to view all flashcards.';
                    this._practiceMessage = 'Unselect practice mode to view all flashcards.';
                }
                break;
            default:
                moveToCardWithField(returnTrue);
        }
    };

    /**
     * Goes to the next Doc in the stack subject to the currently selected filter option.
     */
    advance = (e: React.MouseEvent) => {
        e.stopPropagation();
        this.move(1);
    };

    /**
     * Goes to the previous Doc in the stack subject to the currently selected filter option.
     */
    goback = (e: React.MouseEvent) => {
        e.stopPropagation();
        this.move(-1);
    };

    /*
     * Stars the document when the star button is pressed.
     */
    star = (e: React.MouseEvent) => {
        e.stopPropagation();
        const curDoc = this.carouselItems[NumCast(this.layoutDoc._carousel_index)];
        curDoc.layout[this.starField] = curDoc.layout[this.starField] ? undefined : true;
        // if (!curDoc.layout[this.starField]) this.move(1);
        // this.layoutDoc._carousel_index = undefined;
    };

    /*
     * Sets a flashcard to either missed or correct depending on if they got the question right in practice mode.
     */
    setPracticeVal = (e: React.MouseEvent, val: string) => {
        e.stopPropagation();
        const curDoc = this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)];
        curDoc.layout[this.practiceField] = val;
        this.advance(e);
    };
    captionStyleProvider = (doc: Doc | undefined, captionProps: Opt<FieldViewProps>, property: string): any => {
        // first look for properties on the document in the carousel, then fallback to properties on the container
        const childValue = doc?.['caption_' + property] ? this._props.styleProvider?.(doc, captionProps, property) : undefined;
        return childValue ?? this._props.styleProvider?.(this.layoutDoc, captionProps, property);
    };
    panelHeight = () => this._props.PanelHeight() - (StrCast(this.layoutDoc._layout_showCaption) ? 50 : 0);
    onContentDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick);
    onContentClick = () => ScriptCast(this.layoutDoc.onChildClick);
    captionWidth = () => this._props.PanelWidth() - 2 * this.marginX;

    setPracticeMode = (mode: practiceMode) => {
        this.layoutDoc.practiceMode = mode;
        this.carouselItems?.map(doc => (doc.layout[this.practiceField] = undefined));
        switch (mode) {
            case practiceMode.QUIZ:
                this.carouselItems?.map(doc => (doc.layout[this.sideField] = undefined));
                break;
            case practiceMode.NORMAL:
                this.setPracticeMessage(undefined);
                break;
        }
    };

    setFilterMode = (mode: cardMode) => {
        this.layoutDoc.filterOp = mode;
        switch (mode) {
            case cardMode.STAR:
                this.move(1);
                break;
            default: this.setFilterMessage(undefined); // prettier-ignore
        }
    };

    @computed get content() {
        const index = NumCast(this.layoutDoc._carousel_index);
        const curDoc = this.carouselItems?.[index];
        const captionProps = { ...this._props, NativeScaling: returnOne, PanelWidth: this.captionWidth, fieldKey: 'caption', setHeight: undefined, setContentView: undefined };
        const carouselShowsCaptions = StrCast(this.layoutDoc._layout_showCaption);
        return !(curDoc?.layout instanceof Doc) ? null : (
            <>
                <div className="collectionCarouselView-image" key="image">
                    <DocumentView
                        {...this._props}
                        NativeWidth={returnZero}
                        NativeHeight={returnZero}
                        fitWidth={undefined}
                        setContentViewBox={undefined}
                        onDoubleClickScript={this.onContentDoubleClick}
                        onClickScript={this.onContentClick}
                        isDocumentActive={this._props.childDocumentsActive?.() ? this._props.isDocumentActive : this._props.isContentActive}
                        isContentActive={this._props.childContentsActive ?? this._props.isContentActive() === false ? returnFalse : emptyFunction}
                        hideCaptions={!!carouselShowsCaptions} // hide captions if the carousel is configured to show the captions
                        renderDepth={this._props.renderDepth + 1}
                        LayoutTemplate={this._props.childLayoutTemplate}
                        LayoutTemplateString={this._props.childLayoutString}
                        Document={curDoc.layout}
                        TemplateDataDocument={DocCast(curDoc.layout.resolvedDataDoc)}
                        PanelHeight={this.panelHeight}
                    />
                </div>
                {!carouselShowsCaptions ? null : (
                    <div
                        className="collectionCarouselView-caption"
                        key="caption"
                        onWheel={StopEvent}
                        style={{
                            borderRadius: this._props.styleProvider?.(this.layoutDoc, captionProps, StyleProp.BorderRounding),
                            marginRight: this.marginX,
                            marginLeft: this.marginX,
                            width: `calc(100% - ${this.marginX * 2}px)`,
                        }}>
                        <FormattedTextBox key={index} {...captionProps} fieldKey={carouselShowsCaptions} styleProvider={this.captionStyleProvider} Document={curDoc.layout} TemplateDataDocument={undefined} />
                    </div>
                )}
            </>
        );
    }
    @computed get buttons() {
        if (!this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)]) return null;
        return (
            <>
                <div key="back" className="carouselView-back" onClick={this.goback}>
                    <FontAwesomeIcon icon="chevron-left" size="2x" />
                </div>
                <div key="fwd" className="carouselView-fwd" onClick={this.advance}>
                    <FontAwesomeIcon icon="chevron-right" size="2x" />
                </div>
                <div key="star" className="carouselView-star" onClick={this.star}>
                    <FontAwesomeIcon icon="star" color={this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)].layout[this.starField] ? 'yellow' : 'gray'} size="1x" />
                </div>
                {this.layoutDoc.practiceMode === practiceMode.PRACTICE ? (
                    <div>
                        <div key="remove" className="carouselView-remove" onClick={e => this.setPracticeVal(e, practiceVal.MISSED)}>
                            <FontAwesomeIcon icon="xmark" color="red" size="1x" />
                        </div>
                        <div key="check" className="carouselView-check" onClick={e => this.setPracticeVal(e, practiceVal.CORRECT)}>
                            <FontAwesomeIcon icon="check" color="green" size="1x" />
                        </div>
                    </div>
                ) : null}
            </>
        );
    }

    togglePracticeMode = (mode: practiceMode) => {
        if (mode === this.layoutDoc.practiceMode) this.setPracticeMode(practiceMode.NORMAL);
        else this.setPracticeMode(mode);
    };
    toggleFilterMode = () => { this.layoutDoc.filterOp === cardMode.STAR ? this.setFilterMode(cardMode.ALL) : this.setFilterMode(cardMode.STAR)}; //prettier-ignore
    setColor = (mode: practiceMode | cardMode, which: string) => { return which === mode ? 'white' : 'light gray'}; //prettier-ignore

    @computed get menu() {
        return (
            <div className="carouselView-menu">
                <Tooltip title="Practice flashcards using GPT">
                    <div key="back" className="carouselView-quiz" onClick={e => this.togglePracticeMode(practiceMode.QUIZ)}>
                        <FontAwesomeIcon icon="file-pen" color={this.setColor(practiceMode.QUIZ, StrCast(this.layoutDoc.practiceMode))} size="1x" />
                    </div>
                </Tooltip>
                <Tooltip title={this.layoutDoc.practiceMode === practiceMode.PRACTICE ? 'Exit practice mode' : 'Practice flashcards manually'}>
                    <div key="back" className="carouselView-practice" onClick={e => this.togglePracticeMode(practiceMode.PRACTICE)}>
                        <FontAwesomeIcon icon="check" color={this.setColor(practiceMode.PRACTICE, StrCast(this.layoutDoc.practiceMode))} size="1x" />
                    </div>
                </Tooltip>
                <Tooltip title={this.layoutDoc.filterOp === cardMode.STAR ? 'Show all cards' : 'Show only starred cards'}>
                    <div key="back" className="carouselView-starFilter" onClick={e => this.toggleFilterMode()}>
                        <FontAwesomeIcon icon="filter" color={this.setColor(cardMode.STAR, StrCast(this.layoutDoc.filterOp))} size="1x" />
                    </div>
                </Tooltip>
            </div>
        );
    }

    render() {
        return (
            <div
                className="collectionCarouselView-outer"
                ref={this.createDashEventsTarget}
                style={{
                    background: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor),
                    color: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color),
                }}>
                {!this._practiceMessage && !this._filterMessage ? (
                    this.content
                ) : (
                    <p className="message">
                        {this._filterMessage}
                        {'\n'}
                        {this._practiceMessage}
                    </p>
                )}
                {!this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)] && this.layoutDoc.practiceMode === practiceMode.PRACTICE ? <p className="message">Add flashcards </p> : null}
                <p
                    className="missed-message"
                    style={{
                        color: 'red',
                        fontWeight: 'bold',
                        zIndex: '999',
                        position: 'relative',
                        left: '10px',
                        top: '10px',
                        width: '10px',
                        display: this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)]
                            ? this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)].layout[this.practiceField] === practiceVal.MISSED && this.layoutDoc.practiceMode === practiceMode.PRACTICE && !this._practiceMessage
                                ? 'block'
                                : 'none'
                            : 'none',
                    }}>
                    Recently missed!
                </p>
                {this.menu}
                {this.Document._chromeHidden || (!this._filterMessage && !this._practiceMessage) ? this.buttons : null}
            </div>
        );
    }
}
