import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import * as CSS from 'csstype';
import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import { computedFn } from 'mobx-utils';
import * as React from 'react';
import { ClientUtils, returnFalse, returnNever, returnZero, setupMoveUpEvents } from '../../../ClientUtils';
import { emptyFunction } from '../../../Utils';
import { Doc, DocListCast, Opt } from '../../../fields/Doc';
import { Animation } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
import { List } from '../../../fields/List';
import { ScriptField } from '../../../fields/ScriptField';
import { BoolCast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { DocumentType } from '../../documents/DocumentTypes';
import { Docs } from '../../documents/Documents';
import { DragManager } from '../../util/DragManager';
import { dropActionType } from '../../util/DropActionTypes';
import { SettingsManager } from '../../util/SettingsManager';
import { SnappingManager } from '../../util/SnappingManager';
import { Transform } from '../../util/Transform';
import { undoable, UndoManager } from '../../util/UndoManager';
import { PinDocView, PinProps } from '../PinFuncs';
import { StyleProp } from '../StyleProp';
import { TagItem } from '../TagsView';
import { DocumentView, DocumentViewProps } from '../nodes/DocumentView';
import { FocusViewOptions } from '../nodes/FocusViewOptions';
import './CollectionCardDeckView.scss';
import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';

/**
 * New view type specifically for studying more dynamically. Allows you to reorder docs however you see fit, easily
 * sort and filter using presets, and customize your experience with chat gpt.
 *
 * This file contains code as to how the docs are to be rendered (there place geographically and also in regards to sorting),
 * and callback functions for the gpt popup
 */
@observer
export class CollectionCardView extends CollectionSubView() {
    private _dropDisposer?: DragManager.DragDropDisposer;
    private _disposers: { [key: string]: IReactionDisposer } = {};
    private _oldWheel: HTMLElement | null = null;
    private _dropped = false; // set when a card doc has just moved and the drop method has been called - prevents the pointerUp method from hiding doc decorations (which needs to be done when clicking on a card to animate it to front/center)
    private _setCurDocScript = () => ScriptField.MakeScript('scriptContext.layoutDoc._card_curDoc=this', { scriptContext: 'any' })!;
    private _draggerRef = React.createRef<HTMLDivElement>();

    @observable _forceChildXf = 0;
    @observable _hoveredNodeIndex = -1;
    @observable _docRefs = new ObservableMap<Doc, DocumentView>();
    @observable _cursor: CSS.Property.Cursor = 'ew-resize';

    constructor(props: SubCollectionViewProps) {
        super(props);
        makeObservable(this);
    }
    protected createDashEventsTarget = (ele: HTMLDivElement | null) => {
        this._dropDisposer?.();
        if (ele) {
            this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
        }
        this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
        this._oldWheel = ele;
        // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling
        ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
    };
    @computed get cardWidth() {
        return NumCast(this.layoutDoc._cardWidth, 50);
    }
    @computed get _maxRowCount() {
        return Math.ceil(this.cardDeckWidth / this.cardWidth);
    }

    componentDidMount() {
        this._props.setContentViewBox?.(this);
        // if card deck moves, then the child doc views are hidden so their screen to local transforms will return empty rectangles
        // when inquired from the dom (below in childScreenToLocal).  When the doc is actually rendered, we need to act like the
        // dash data just changed and trigger a React involidation with the correct data (read from the dom).
        this._disposers.child = reaction(
            () => [this.Document.x, this.Document.y],
            () => {
                if (!Array.from(this._docRefs.values()).every(dv => dv.ContentDiv?.getBoundingClientRect().width)) {
                    setTimeout(action(() => this._forceChildXf++));
                }
            }
        );
        this._disposers.select = reaction(
            () => this.childDocs.find(d => this._docRefs.get(d)?.IsSelected),
            selected => {
                selected && (this.layoutDoc._card_curDoc = selected);
            }
        );
    }

    componentWillUnmount() {
        Object.keys(this._disposers).forEach(key => this._disposers[key]?.());
        this._dropDisposer?.();
    }

    /**
     * Number of rows of cards to be rendered
     */
    @computed get numRows() {
        return Math.ceil(this.childDocs.length / this._maxRowCount);
    }
    /**
     * Circle arc size, in radians, to layout cards
     */
    @computed get archAngle() {
        return NumCast(this.layoutDoc.card_arch, 90) * (Math.PI / 180) * (this.childDocsNoInk.length < this._maxRowCount ? this.childDocsNoInk.length / this._maxRowCount : 1);
    }
    /**
     * Spacing card rows as a percent of Doc size.   100 means rows spread out to fill 100% of the Doc vertically.  Default is 60%
     */
    @computed get cardSpacing() {
        return NumCast(this.layoutDoc.card_spacing, 60);
    }

    /**
     * The child documents to be rendered-- everything other than ink/link docs (which are marks as being svg's)
     */
    @computed get childDocsNoInk() {
        return this.childLayoutPairs.filter(pair => !pair.layout.layout_isSvg);
    }

    /**
     * how much to scale down the contents of the view so that everything will fit
     */
    @computed get fitContentScale() {
        const length = Math.min(this.childDocsNoInk.length, this._maxRowCount);
        return (this.childPanelWidth() * length) / (this._props.PanelWidth() - 2 * this.xMargin);
    }

    @computed get nativeScaling() {
        return this._props.NativeDimScaling?.() || 1;
    }

    @computed get xMargin() {
        return NumCast(this.layoutDoc._xMargin, Math.max(3, 0.05 * this._props.PanelWidth()));
    }

    @computed get yMargin() {
        return this._props.yPadding || NumCast(this.layoutDoc._yMargin, Math.min(5, 0.05 * this._props.PanelWidth()));
    }

    @computed get cardDeckWidth() {
        return this._props.PanelWidth() - 2 * this.xMargin;
    }

    setHoveredNodeIndex = action((index: number) => {
        if (!SnappingManager.IsDragging) this._hoveredNodeIndex = index;
    });

    isSelected = (doc: Doc) => this._docRefs.get(doc)?.IsSelected;
    childPanelWidth = () => NumCast(this.layoutDoc.childPanelWidth, Math.max(150, this._props.PanelWidth() / (this.childDocsNoInk.length > this._maxRowCount ? this._maxRowCount : this.childDocsNoInk.length) / this.nativeScaling));
    childPanelHeight = () => this._props.PanelHeight() * this.fitContentScale;
    onChildDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick);
    isContentActive = () => this._props.isSelected() || this._props.isContentActive() || this.isAnyChildContentActive();
    isAnyChildContentActive = this._props.isAnyChildContentActive;

    /**
     * When dragging a card, determines the index the card should be set to if dropped
     * @param mouseX mouse's x location
     * @param mouseY mouses' y location
     * @returns the card's new index
     */
    findCardDropIndex = (mouseX: number, mouseY: number) => {
        const cardCount = this.childDocs.length;
        let index = 0;
        const cardWidth = cardCount < this._maxRowCount ? this._props.PanelWidth() / cardCount : this._props.PanelWidth() / this._maxRowCount;

        // Calculate the adjusted X position accounting for the initial offset
        let adjustedX = mouseX;

        const rowHeight = this._props.PanelHeight() / this.numRows;
        const currRow = Math.floor((mouseY - 100) / rowHeight); //rows start at 0

        if (adjustedX < 0) {
            return 0; // Before the first column
        }

        if (cardCount < this._maxRowCount) {
            index = Math.floor(adjustedX / cardWidth);
        } else if (currRow != this.numRows - 1) {
            index = Math.floor(adjustedX / cardWidth) + currRow * this._maxRowCount;
        } else {
            const cardsInRow = cardCount - currRow * this._maxRowCount;
            const offset = ((this._maxRowCount - cardsInRow) / 2) * cardWidth;
            adjustedX = mouseX - offset;

            index = Math.floor(adjustedX / cardWidth) + currRow * this._maxRowCount;
        }
        return index;
    };

    /**
     * if pointer moves over cardDeck while dragging a Doc that is in the Deck or that can be dropped in the deck,
     * then this sets the card index where the dragged card would be added.
     */
    @action
    onPointerMove = (x: number, y: number) => {
        if (DragManager.docsBeingDragged.some(doc => this.childDocs.includes(doc)) || SnappingManager.CanEmbed) {
            this.docDraggedIndex = this.findCardDropIndex(x, y);
        }
    };

    /**
     * Resets all the doc dragging vairables once a card is dropped
     * @param e
     * @param de drop event
     * @returns true if a card has been dropped, falls if not
     */
    onInternalDrop = undoable(
        action((e: Event, de: DragManager.DropEvent) => {
            if (de.complete.docDragData) {
                const dragIndex = this.docDraggedIndex;
                const draggedDoc = DragManager.docsBeingDragged[0];
                if (dragIndex > -1 && draggedDoc) {
                    this.docDraggedIndex = -1;
                    const sorted = this.childDocs;
                    const originalIndex = sorted.findIndex(doc => doc === draggedDoc);

                    this.Document[this._props.fieldKey + '_sort'] = '';
                    originalIndex !== -1 && sorted.splice(originalIndex, 1);
                    sorted.splice(dragIndex, 0, draggedDoc);
                    if (de.complete.docDragData.removeDocument?.(draggedDoc)) {
                        this.dataDoc[this.fieldKey] = new List<Doc>(sorted);
                    }
                    this._dropped = true;
                }
                e.stopPropagation();
                return true;
            }
            return false;
        }),
        ''
    );

    /**
     * Used to determine how to sort cards based on tags. The leftmost tags are given lower values while cards to the right are
     * given higher values. Decimals are used to determine placement for cards with multiple tags
     * @param doc the doc whose value is being determined
     * @returns its value based on its tags
     */

    tagValue = (doc: Doc) =>
        Doc.MyFilterHotKeys.map((key, i) => ({ has: TagItem.docHasTag(doc, StrCast(key.toolType)), i }))
            .filter(({ has }) => has)
            .map(({ i }) => i)
            .join('.');

    isChildContentActive = computedFn(
        (doc: Doc) => () =>
            this._props.isContentActive?.() === false
                ? false
                : this._props.isDocumentActive?.() && this.curDoc() === doc
                  ? true
                  : this._props.childDocumentsActive?.() === false || this.Document.childDocumentsActive === false
                    ? false
                    : undefined
    ); // prettier-ignore

    displayDoc = (doc: Doc, screenToLocalTransform: () => Transform) => (
        <DocumentView
            {...this._props}
            ref={action((r: DocumentView) => (!r?.ContentDiv ? this._docRefs.delete(doc) : this._docRefs.set(doc, r)))}
            Document={doc}
            NativeWidth={returnZero}
            NativeHeight={returnZero}
            PanelWidth={this.childPanelWidth}
            PanelHeight={this.childPanelHeight}
            renderDepth={this._props.renderDepth + 1}
            LayoutTemplate={this._props.childLayoutTemplate}
            LayoutTemplateString={this._props.childLayoutString}
            containerViewPath={this.childContainerViewPath}
            ScreenToLocalTransform={screenToLocalTransform} // makes sure the box wrapper thing is in the right spot
            isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive}
            isContentActive={this.isChildContentActive(doc)}
            fitWidth={returnFalse}
            waitForDoubleClickToClick={returnNever}
            scriptContext={this}
            focus={this.focus}
            onDoubleClickScript={this.onChildDoubleClick}
            onClickScript={this.curDoc() === doc ? undefined : this._setCurDocScript}
            dontCenter="y" // Don't center it vertically, because the grid it's in is already doing that and we don't want to do it twice.
            dragAction={(this.Document.childDragAction ?? this._props.childDragAction) as dropActionType}
            showTags={BoolCast(this.layoutDoc.showChildTags) || BoolCast(this.Document._layout_showTags)}
            whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
            dontHideOnDrag
        />
    );

    /**
     * Determines how many cards are in the row of a card at a specific index
     * @param index numerical index of card in total list of all cards
     * @returns number of cards in row that contains index
     */
    cardsInRowThatIncludesCardIndex = (index: number) => {
        if (this.childDocsNoInk.length < this._maxRowCount) {
            return this.childDocsNoInk.length;
        }
        const totalCards = this.childDocsNoInk.length;
        if (index < totalCards - (totalCards % this._maxRowCount)) {
            return this._maxRowCount;
        }
        return totalCards % this._maxRowCount;
    };
    /**
     * Determines the index a card is in in a row.  If the row is not full, then the cards
     * are centered within the row (as if unrendered cards had been added to the start and end
     * of the row) and the retuned index is the index the card in this virtual full row.
     * @param index numerical index of card in total list of all cards
     * @returns index of card in its row, normalized to a full size row
     */
    centeredIndexOfCardInRow = (index: number) => {
        const cardsInRow = this.cardsInRowThatIncludesCardIndex(index);
        const lineIndex = index % this._maxRowCount;
        if (cardsInRow === this._maxRowCount) return lineIndex;
        return lineIndex + (this._maxRowCount - cardsInRow) / 2;
    };
    /**
     * Returns the rotation of a card in radians based on its horizontal location (and thus m apping to a circle arc).
     * The amount of rotation is goverend by the Doc's card_arch field which specifies, in degrees, the range of a circle
     * arc that cards should cover -- by default, -45 to 45 degrees.
     * @param index numerical index of card in total list of all cards
     * @returns angle of rotation in radians
     */
    rotate = (index: number) => {
        const cardsInRow = this.cardsInRowThatIncludesCardIndex(index);
        const centeredIndexInRow = (cardsInRow < this._maxRowCount ? index + (this._maxRowCount - cardsInRow) / 2 : index) % this._maxRowCount;
        const rowIndexMax = this._maxRowCount - 1;
        return ((this.archAngle / 2) * (centeredIndexInRow - rowIndexMax / 2)) / (rowIndexMax / 2);
    };
    /**
     * Provides a vertical adjustment to a card's grid position so that it will lie along an arch.
     * @param index numerical index of card in total list of all cards
     */
    translateY = (index: number) => {
        const Magnitude = ((this._props.PanelHeight() * this.fitContentScale) / 2) * Math.sqrt(((this.archAngle * (180 / Math.PI)) / 60) * 4);
        return Magnitude * (1 - Math.sin(this.rotate(index) + Math.PI / 2) - (1 - Math.sin(this.archAngle / 2 + Math.PI / 2)) / 2);
    };
    /**
     * When the card index is for a row (not the first row) that is not full, this returns a horizontal adjustment that centers the row
     * @param index index of card from start of deck
     * @param cardsInRow number of cards in the row containing the indexed card
     * @returns horizontal pixel translation
     */
    horizontalAdjustmentForPartialRows = (index: number, cardsInRow: number) => (index < this._maxRowCount ? 0 : (this._maxRowCount - cardsInRow) * (this.childPanelWidth() / 2));

    /**
     * Adjusts the vertical placement of the card from its grid position so that it will either line on a
     * circular arc if the card isn't active, or so that it will be centered otherwise.
     * @param isActive whether the card is focused for interaction
     * @param index index of card from start of deck
     * @returns vertical pixel translation
     */
    adjustCardYtoFitArch = (isActive: boolean, index: number) => {
        const rowHeight = this._props.PanelHeight() / this.numRows;
        const rowIndex = Math.floor(index / this._maxRowCount);
        const rowToCenterShift = this.numRows / 2 - rowIndex;
        return isActive
            ? (rowToCenterShift * rowHeight - rowHeight / 2) * ((this.cardSpacing * this.fitContentScale) / 100) //
            : this.translateY(index);
    };

    childScreenToLocal = computedFn((doc: Doc, index: number, isSelected: boolean) => () => {
        // need to explicitly trigger an invalidation since we're reading everything from the Dom
        this._forceChildXf;
        this._props.ScreenToLocalTransform();

        const dref = this._docRefs.get(doc);
        const { translateX, translateY, scale } = ClientUtils.GetScreenTransform(dref?.ContentDiv);
        if (!scale) return new Transform(0, 0, 1);

        return new Transform(-translateX + (dref?.centeringX || 0) * scale, 
                             -translateY + (dref?.centeringY || 0) * scale, 1)
                  .scale(1 / scale).rotate(!isSelected ? -this.rotate(this.centeredIndexOfCardInRow(index)) : 0); // prettier-ignore
    });

    /**
     * Releases the currently focused Doc by deselecting it and returning it to its location on the arch, and selecting the
     * cardDeck itself.
     * This will also force the Doc to recompute its layout transform when the animation completes.
     * In addition, this sets an animating flag on the Doc so that it will receive no poiner events when animating, such as hover
     * events that would trigger a flashcard to flip.
     * @param doc doc that will be animated away from center focus
     */
    releaseCurDoc = action(() => {
        const selDoc = this.curDoc();
        this.layoutDoc._card_curDoc = undefined;
        const cardDocView = DocumentView.getDocumentView(selDoc, this.DocumentView?.());
        if (cardDocView && selDoc) {
            DocumentView.DeselectView(cardDocView);
            this._props.select(false);
            selDoc[Animation] = selDoc; // turns off pointer events & doc decorations while animating - useful for flashcards that reveal back on hover
            setTimeout(action(() => {
                selDoc[Animation] = undefined;
                this._forceChildXf++;
            }), 350); // prettier-ignore
        }
    });

    cardSizerDown = (e: React.PointerEvent) => {
        runInAction(() => {
            this._cursor = 'grabbing';
        });
        const batch = UndoManager.StartBatch('card view size');
        setupMoveUpEvents(
            this,
            e,
            (emove: PointerEvent) => {
                this.layoutDoc._cardWidth = Math.max(10, this.ScreenToLocalBoxXf().transformPoint(emove.clientX, 0)[0] - this.xMargin);
                return false;
            },
            action(() => {
                this._cursor = 'ew-resize';
                batch.end();
            }),
            emptyFunction
        );
    };

    /**
     * turns off the _dropped flag at the end of a drag/drop, or releases the focused Doc if a different Doc is clicked
     */
    cardPointerUp = action((doc: Doc) => {
        if (this.curDoc() === doc || this._dropped) {
            this._dropped = false;
        } else {
            this.releaseCurDoc(); // NOTE: the onClick script for the card will select the new card (ie, 'doc')
        }
    });

    focus = action((anchor: Doc, options: FocusViewOptions): Opt<number> => {
        const docs = DocListCast(this.Document[this.fieldKey]);
        if (anchor.type === DocumentType.CONFIG || docs.includes(anchor)) {
            const foundDoc = DocCast(
                anchor.config_card_curDoc,
                docs.find(doc => doc === DocCast(anchor.annotationOn, anchor))
            );
            options.didMove = foundDoc !== this.curDoc() ? true : false;
            options.didMove && (this.layoutDoc._card_curDoc = foundDoc);
        }
        return undefined;
    });
    getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
        const anchor = Docs.Create.ConfigDocument({ annotationOn: this.Document, config_card_curDoc: this.curDoc() });
        PinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { collectionType: true, filters: true } }, this.Document);
        addAsAnnotation && Doc.AddDocToList(this.dataDoc, this.fieldKey + '_annotations', anchor); // when added as an annotation, links to anchors can be found as links to the document even if the anchors are not rendered
        return anchor;
    };
    addDocTab = this.addLinkedDocTab;

    /**
     * Actually renders all the cards
     */
    @computed get renderCards() {
        // Map sorted documents to their rendered components
        return this.childDocs.map((doc, index) => {
            const cardsInRow = this.cardsInRowThatIncludesCardIndex(index);

            const childScreenToLocal = this.childScreenToLocal(doc, index, doc === this.curDoc());

            const translateToCenterIfActive = () => (doc === this.curDoc() ? (cardsInRow / 2 - (index % this._maxRowCount)) * 100 - 50 : 0);

            const aspect = NumCast(doc.height) / NumCast(doc.width, 1);
            const vscale = Math.max(1,Math.min((this._props.PanelHeight() * 0.95 * this.fitContentScale * this.nativeScaling) / (aspect * this.childPanelWidth()), 
                                    (this._props.PanelHeight() - 80) / (aspect * (this._props.PanelWidth() / 10)))); // prettier-ignore
            const hscale = Math.min(this.childDocs.length, this._maxRowCount) / 2; // bcz: hack - the grid is divided evenly into maxRowCount cells, so the max scaling would be maxRowCount -- but making things that wide is ugly, so cap it off at half the window size
            return (
                <div
                    key={doc[Id]}
                    className={`card-item${doc === this.curDoc() ? '-active' : this.isAnyChildContentActive() ? '-inactive' : ''}`}
                    onPointerUp={() => this.cardPointerUp(doc)}
                    style={{
                        width: this.childPanelWidth(),
                        height: 'max-content',
                        transform: `translateY(${this.adjustCardYtoFitArch(doc === this.curDoc(), index)}px)
                                    translateX(calc(${translateToCenterIfActive()}% + ${this.horizontalAdjustmentForPartialRows(index, cardsInRow)}px))
                                    rotate(${doc !== this.curDoc()? this.rotate(index) : 0}rad)
                                    scale(${doc === this.curDoc()? `${Math.min(hscale, vscale) * 100}%` : this._hoveredNodeIndex === index ? 1.1 : 1})`,
                    }} // prettier-ignore
                    onPointerEnter={() => this.setHoveredNodeIndex(index)}
                    onPointerLeave={() => this.setHoveredNodeIndex(-1)}>
                    {this.displayDoc(doc, childScreenToLocal)}
                </div>
            );
        });
    }
    onPassiveWheel = (e: WheelEvent) => e.stopPropagation();

    contentScreenToLocalXf = () => this._props.ScreenToLocalTransform().scale(this._props.NativeDimScaling?.() || 1);
    docViewProps = (): DocumentViewProps => ({
        ...this._props, //
        isDocumentActive: this._props.childDocumentsActive?.() ? this._props.isDocumentActive : this._props.isContentActive,
        isContentActive: emptyFunction,
        ScreenToLocalTransform: this.contentScreenToLocalXf,
    });
    answered = () => {
        this.layoutDoc._card_curDoc = this.curDoc() ? this.filteredChildDocs()[(this.filteredChildDocs().findIndex(d => d === this.curDoc()) + 1) % (this.filteredChildDocs().length || 1)] : undefined;
    };
    curDoc = () => DocCast(this.layoutDoc._card_curDoc);

    render() {
        const fitContentScale = this.childDocsNoInk.length === 0 ? 1 : this.fitContentScale;
        return (
            <div
                className="collectionCardView-outer"
                ref={(ele: HTMLDivElement | null) => this.createDashEventsTarget(ele)}
                onPointerDown={e => e.button !== 2 && !e.ctrlKey && this.releaseCurDoc()}
                onPointerLeave={action(() => (this.docDraggedIndex = -1))}
                onPointerMove={e => this.onPointerMove(...this._props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY))}
                onDrop={this.onExternalDrop.bind(this)}
                style={{
                    background: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor) as string,
                    color: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) as string,
                    paddingLeft: this.xMargin,
                    paddingRight: this.xMargin,
                }}>
                <div
                    className="collectionCardView-inner"
                    style={{
                        transform: `scale(${1 / fitContentScale})`,
                        height: `${100 * fitContentScale}%`,
                        width: `${100 * fitContentScale}%`,
                        top: this.yMargin,
                    }}>
                    <div
                        className="collectionCardView-cardwrapper"
                        style={{
                            gridTemplateColumns: `repeat(${this._maxRowCount}, 1fr)`,
                            gridAutoRows: `${100 / this.numRows}%`,
                            height: `${this.cardSpacing}%`,
                        }}>
                        {this.renderCards}
                    </div>
                    <div
                        className="collectionCardView-flashcardUI"
                        style={{
                            pointerEvents: this.childDocsNoInk.length === 0 ? undefined : 'none',
                            height: `${100 / this.nativeScaling / fitContentScale}%`,
                            width: `${100 / this.nativeScaling / fitContentScale}%`,
                            transform: `scale(${this.nativeScaling * fitContentScale})`,
                        }}>
                        {this.flashCardUI(this.curDoc, this.docViewProps, this.answered)}
                    </div>
                </div>

                <div
                    className="collectionCardView-cardSizeDragger"
                    onPointerDown={this.cardSizerDown}
                    ref={this._draggerRef}
                    style={{ display: this._props.isContentActive() ? undefined : 'none', cursor: this._cursor, color: SettingsManager.userColor, left: `${this.cardWidth + this.xMargin}px` }}>
                    <FontAwesomeIcon icon="arrows-alt-h" />
                </div>
            </div>
        );
    }
}
