import { action, computed, IReactionDisposer, makeObservable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc, DocListCast } from '../../../fields/Doc';
import { ScriptField } from '../../../fields/ScriptField';
import { NumCast, StrCast } from '../../../fields/Types';
import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../Utils';
import { DocUtils } from '../../documents/Documents';
import { SelectionManager } from '../../util/SelectionManager';
import { undoBatch, UndoManager } from '../../util/UndoManager';
import { OpenWhere } from '../nodes/DocumentView';
import { computePassLayout, computeStarburstLayout } from './collectionFreeForm';
import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
import './CollectionPileView.scss';
import { CollectionSubView } from './CollectionSubView';

@observer
export class CollectionPileView extends CollectionSubView() {
    _originalChrome: any = '';
    _disposers: { [name: string]: IReactionDisposer } = {};

    constructor(props: any) {
        super(props);
        makeObservable(this);
    }

    componentDidMount() {
        if (this.layoutEngine() !== computePassLayout.name && this.layoutEngine() !== computeStarburstLayout.name) {
            this.Document._freeform_pileEngine = computePassLayout.name;
        }
        this._originalChrome = this.layoutDoc._chromeHidden;
        this.layoutDoc._chromeHidden = true;
    }
    componentWillUnmount() {
        this.layoutDoc._chromeHidden = this._originalChrome;
        Object.values(this._disposers).forEach(disposer => disposer?.());
    }

    layoutEngine = () => StrCast(this.Document._freeform_pileEngine);

    @undoBatch
    addPileDoc = (doc: Doc | Doc[]) => {
        (doc instanceof Doc ? [doc] : doc).map(d => DocUtils.iconify(d));
        return this._props.addDocument?.(doc) || false;
    };

    @undoBatch
    removePileDoc = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => {
        (doc instanceof Doc ? [doc] : doc).forEach(d => Doc.deiconifyView(d));
        const ret = this._props.moveDocument?.(doc, targetCollection, addDoc) || false;
        if (ret && !DocListCast(this.dataDoc[this.fieldKey ?? 'data']).length) this._props.DocumentView?.()._props.removeDocument?.(this.Document);
        return ret;
    };

    @computed get toggleIcon() {
        return ScriptField.MakeScript('documentView.iconify()', { documentView: 'any' });
    }
    @computed get contentEvents() {
        const isStarburst = this.layoutEngine() === computeStarburstLayout.name;
        return this._props.isContentActive() && isStarburst ? undefined : 'none';
    }

    // returns the contents of the pileup in a CollectionFreeFormView
    @computed get contents() {
        return (
            <div className="collectionPileView-innards" style={{ pointerEvents: this.contentEvents }}>
                <CollectionFreeFormView
                    {...this._props} //
                    layoutEngine={this.layoutEngine}
                    addDocument={this.addPileDoc}
                    moveDocument={this.removePileDoc}
                    // pile children never have their contents active, but will be document active whenever the entire pile is.
                    childContentsActive={returnFalse}
                    childDocumentsActive={this._props.isDocumentActive}
                    childDragAction="move"
                    childClickScript={this.toggleIcon}
                />
            </div>
        );
    }

    // toggles the pileup between starburst to compact
    toggleStarburst = action(() => {
        this.layoutDoc._freeform_scale = undefined;
        if (this.layoutEngine() === computeStarburstLayout.name) {
            if (NumCast(this.layoutDoc._width) !== NumCast(this.Document._starburstDiameter, 500)) {
                this.Document._starburstDiameter = NumCast(this.layoutDoc._width);
            }
            const defaultSize = 110;
            this.Document.x = NumCast(this.Document.x) + NumCast(this.layoutDoc._width) / 2 - NumCast(this.layoutDoc._freeform_pileWidth, defaultSize) / 2;
            this.Document.y = NumCast(this.Document.y) + NumCast(this.layoutDoc._height) / 2 - NumCast(this.layoutDoc._freeform_pileHeight, defaultSize) / 2;
            this.layoutDoc._width = NumCast(this.layoutDoc._freeform_pileWidth, defaultSize);
            this.layoutDoc._height = NumCast(this.layoutDoc._freeform_pileHeight, defaultSize);
            DocUtils.pileup(this.childDocs, undefined, undefined, NumCast(this.layoutDoc._width) / 2, false);
            this.layoutDoc._freeform_panX = 0;
            this.layoutDoc._freeform_panY = -10;
            this.Document._freeform_pileEngine = computePassLayout.name;
        } else {
            const defaultSize = NumCast(this.Document._starburstDiameter, 400);
            this.Document.x = NumCast(this.Document.x) + NumCast(this.layoutDoc._width) / 2 - defaultSize / 2;
            this.Document.y = NumCast(this.Document.y) + NumCast(this.layoutDoc._height) / 2 - defaultSize / 2;
            this.layoutDoc._freeform_pileWidth = NumCast(this.layoutDoc._width);
            this.layoutDoc._freeform_pileHeight = NumCast(this.layoutDoc._height);
            this.layoutDoc._freeform_panX = this.layoutDoc._freeform_panY = 0;
            this.layoutDoc._width = this.layoutDoc._height = defaultSize;
            this.layoutDoc.background;
            this.Document._freeform_pileEngine = computeStarburstLayout.name;
        }
    });

    // for dragging documents out of the pileup view
    _undoBatch: UndoManager.Batch | undefined;
    pointerDown = (e: React.PointerEvent) => {
        let dist = 0;
        setupMoveUpEvents(
            this,
            e,
            (e: PointerEvent, down: number[], delta: number[]) => {
                if (this.layoutEngine() === 'pass' && this.childDocs.length && e.shiftKey) {
                    dist += Math.sqrt(delta[0] * delta[0] + delta[1] * delta[1]);
                    if (dist > 100) {
                        if (!this._undoBatch) {
                            this._undoBatch = UndoManager.StartBatch('layout pile');
                        }
                        const doc = this.childDocs[0];
                        doc.x = e.clientX;
                        doc.y = e.clientY;
                        this._props.addDocTab(doc, OpenWhere.inParentFromScreen) && (this._props.removeDocument?.(doc) || false);
                        dist = 0;
                    }
                }
                return false;
            },
            () => {
                this._undoBatch?.end();
                this._undoBatch = undefined;
            },
            emptyFunction,
            e.shiftKey && this.layoutEngine() === computePassLayout.name,
            this.layoutEngine() === computePassLayout.name && e.shiftKey
        ); // this sets _doubleTap
    };

    // onClick for toggling the pileup view
    @undoBatch
    onClick = (e: React.MouseEvent) => {
        if (e.button === 0) {
            SelectionManager.DeselectAll();
            this.toggleStarburst();
            e.stopPropagation();
        }
    };

    render() {
        return (
            <div className={`collectionPileView`} onClick={this.onClick} onPointerDown={this.pointerDown} style={{ width: this._props.PanelWidth(), height: '100%' }}>
                {this.contents}
            </div>
        );
    }
}
