/* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable jsx-a11y/click-events-have-key-events */
import { action, computed, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { returnEmptyDoclist, returnEmptyFilter, returnTrue } from '../../../ClientUtils';
import { emptyFunction } from '../../../Utils';
import { CreateLinkToActiveAudio, Doc, DocListCast, Opt } from '../../../fields/Doc';
import { InkTool } from '../../../fields/InkField';
import { Cast, NumCast, StrCast, toList } from '../../../fields/Types';
import { SnappingManager } from '../../util/SnappingManager';
import { Transform } from '../../util/Transform';
import { GestureOverlay } from '../GestureOverlay';
import { DefaultStyleProvider } from '../StyleProvider';
import { DocumentView } from '../nodes/DocumentView';
import { OpenWhere } from '../nodes/OpenWhere';
import { ExploreView } from './ExploreView';
import { IBounds, emptyBounds } from './ExploreView/utils';
import { NewLightboxHeader } from './Header';
import './NewLightboxView.scss';
import { RecommendationList } from './RecommendationList';
import { IRecommendation } from './components';

// enum LightboxStatus {
//     RECOMMENDATIONS = 'recommendations',
//     ANNOTATIONS = 'annotations',
//     NONE = 'none',
// }

interface LightboxViewProps {
    PanelWidth: number;
    PanelHeight: number;
    maxBorder: number[];
}

type LightboxSavedState = {
    panX: Opt<number>;
    panY: Opt<number>;
    scale: Opt<number>;
    scrollTop: Opt<number>;
    layout_fieldKey: Opt<string>;
};
@observer
export class NewLightboxView extends React.Component<LightboxViewProps> {
    @observable private static _layoutTemplate: Opt<Doc> = undefined;
    @observable private static _layoutTemplateString: Opt<string> = undefined;
    @observable private static _doc: Opt<Doc> = undefined;
    @observable private static _docTarget: Opt<Doc> = undefined;
    @observable private static _docFilters: string[] = []; // filters
    private static _savedState: Opt<LightboxSavedState> = undefined;
    private static _history: Opt<{ doc: Doc; target?: Doc }[]> = [];
    @observable private static _future: Opt<Doc[]> = [];
    @observable private static _docView: Opt<DocumentView> = undefined;

    // keywords
    @observable private static _keywords: string[] = [];
    @observable private static _query: string = '';
    @observable private static _recs: IRecommendation[] = [];
    @observable private static _bounds: IBounds = emptyBounds;
    @observable private static _explore: Opt<boolean> = false;
    @observable private static _sidebarStatus: Opt<string> = '';
    static path: { doc: Opt<Doc>; target: Opt<Doc>; history: Opt<{ doc: Doc; target?: Doc }[]>; future: Opt<Doc[]>; saved: Opt<LightboxSavedState> }[] = [];
    private static LightboxDocTemplate = () => NewLightboxView._layoutTemplate;
    public static GetSavedState(doc: Doc) {
        return this.LightboxDoc === doc && this._savedState ? this._savedState : undefined;
    }
    // adds a cookie to the newLightbox view - the cookie becomes part of a filter which will display any documents whose cookie metadata field matches this cookie
    @action
    public static SetCookie(cookie: string) {
        if (this.LightboxDoc && cookie) {
            this._docFilters = (f => (this._docFilters ? [this._docFilters.push(f) as any, this._docFilters][1] : [f]))(`cookies:${cookie}:provide`);
        }
    }
    public static AddDocTab = (docsIn: Doc | Doc[], location: OpenWhere, layoutTemplate?: Doc | string) => {
        DocumentView.DeselectAll();
        const doc = toList(docsIn).lastElement();
        return (
            doc &&
            NewLightboxView.SetNewLightboxDoc(
                doc,
                undefined,
                [...DocListCast(doc[Doc.LayoutFieldKey(doc)]), ...DocListCast(doc[Doc.LayoutFieldKey(doc) + '_annotations']).filter(anno => anno.annotationOn !== doc), ...(NewLightboxView._future ?? [])].sort(
                    (a: Doc, b: Doc) => NumCast(b._timecodeToShow) - NumCast(a._timecodeToShow)
                ),
                layoutTemplate
            )
        );
    };

    @action public static SetNewLightboxDoc(doc: Opt<Doc>, target?: Doc, future?: Doc[], layoutTemplate?: Doc | string) {
        if (this.LightboxDoc && this.LightboxDoc !== doc && this._savedState) {
            if (this._savedState.panX !== undefined) this.LightboxDoc._freeform_panX = this._savedState.panX;
            if (this._savedState.panY !== undefined) this.LightboxDoc._freeform_panY = this._savedState.panY;
            if (this._savedState.scrollTop !== undefined) this.LightboxDoc._layout_scrollTop = this._savedState.scrollTop;
            if (this._savedState.scale !== undefined) this.LightboxDoc._freeform_scale = this._savedState.scale;
            this.LightboxDoc.layout_fieldKey = this._savedState.layout_fieldKey;
        }
        if (!doc) {
            this._docFilters && (this._docFilters.length = 0);
            this._future = this._history = [];
            Doc.ActiveTool = InkTool.None;
            SnappingManager.SetExploreMode(false);
        } else {
            const l = CreateLinkToActiveAudio(() => doc).lastElement();
            l && (Cast(l.link_anchor_2, Doc, null).backgroundColor = 'lightgreen');
            DocumentView.CurrentlyPlaying?.forEach(dv => dv.ComponentView?.Pause?.());
            // DocumentView.PinDoc(doc, { hidePresBox: true });
            this._history ? this._history.push({ doc, target }) : (this._history = [{ doc, target }]);
            if (doc !== DocumentView.LightboxDoc()) {
                this._savedState = {
                    layout_fieldKey: StrCast(doc.layout_fieldKey),
                    panX: Cast(doc.freeform_panX, 'number', null),
                    panY: Cast(doc.freeform_panY, 'number', null),
                    scale: Cast(doc.freeform_scale, 'number', null),
                    scrollTop: Cast(doc.layout_scrollTop, 'number', null),
                };
            }
        }
        if (future) {
            this._future = [
                ...(this._future ?? []),
                ...(this.LightboxDoc ? [this.LightboxDoc] : []),
                ...future
                    .slice()
                    .sort((a, b) => NumCast(b._timecodeToShow) - NumCast(a._timecodeToShow))
                    .sort((a, b) => Doc.Links(a).length - Doc.Links(b).length),
            ];
        }
        this._doc = doc;
        this._layoutTemplate = layoutTemplate instanceof Doc ? layoutTemplate : undefined;
        if (doc && (typeof layoutTemplate === 'string' ? layoutTemplate : undefined)) {
            doc.layout_fieldKey = layoutTemplate;
        }
        this._docTarget = target || doc;

        return true;
    }
    public static IsNewLightboxDocView(path: DocumentView[]) {
        return (path ?? []).includes(this._docView!);
    }
    @action public static Next() {
        const doc = NewLightboxView._doc!;
        const target = (NewLightboxView._docTarget = this._future?.pop());
        const targetDocView = target && DocumentView.getLightboxDocumentView(target);
        if (targetDocView && target) {
            const l = CreateLinkToActiveAudio(() => targetDocView.ComponentView?.getAnchor?.(true) || target).lastElement();
            l && (Cast(l.link_anchor_2, Doc, null).backgroundColor = 'lightgreen');
            DocumentView.showDocument(target, { willZoomCentered: true, zoomScale: 0.9 });
            if (NewLightboxView._history?.lastElement().target !== target) NewLightboxView._history?.push({ doc, target });
        } else if (!target && NewLightboxView.path.length) {
            const saved = NewLightboxView._savedState;
            const lightboxDoc = DocumentView.LightboxDoc();
            if (lightboxDoc && saved) {
                lightboxDoc._freeform_panX = saved.panX;
                lightboxDoc._freeform_panY = saved.panY;
                lightboxDoc._freeform_scale = saved.scale;
                lightboxDoc._layout_scrollTop = saved.scrollTop;
            }
            const pop = NewLightboxView.path.pop();
            if (pop) {
                NewLightboxView._doc = pop.doc;
                NewLightboxView._docTarget = pop.target;
                NewLightboxView._future = pop.future;
                NewLightboxView._history = pop.history;
                NewLightboxView._savedState = pop.saved;
            }
        } else {
            NewLightboxView.SetNewLightboxDoc(target);
        }
    }

    @action public static Previous() {
        const previous = NewLightboxView._history?.pop();
        if (!previous || !NewLightboxView._history?.length) {
            NewLightboxView.SetNewLightboxDoc(undefined);
            return;
        }
        const { doc, target } = NewLightboxView._history?.lastElement() ?? { doc: undefined, target: undefined };
        const docView = DocumentView.getLightboxDocumentView(target || doc);
        if (docView) {
            NewLightboxView._docTarget = target;
            target && DocumentView.showDocument(target, { willZoomCentered: true, zoomScale: 0.9 });
        } else {
            NewLightboxView.SetNewLightboxDoc(doc, target);
        }
        if (NewLightboxView._future?.lastElement() !== previous.target || previous.doc) NewLightboxView._future?.push(previous.target || previous.doc);
    }

    @action public static SetKeywords(kw: string[]) {
        this._keywords = kw;
    }
    @computed public static get Keywords() {
        return this._keywords;
    }
    @computed public static get LightboxDoc() {
        return this._doc;
    }

    // query
    @action public static SetQuery(query: string) {
        this._query = query;
    }
    @computed public static get Query() {
        return this._query;
    }

    // keywords
    @action public static SetRecs(recs: IRecommendation[]) {
        this._recs = recs;
    }
    @computed public static get Recs() {
        return this._recs;
    }

    // bounds
    @action public static SetBounds(bounds: IBounds) {
        this._bounds = bounds;
    }
    @computed public static get Bounds() {
        return this._bounds;
    }
    // newLightbox sidebar status
    @action public static SetSidebarStatus(sidebarStatus: Opt<string>) {
        this._sidebarStatus = sidebarStatus;
    }

    // explore
    @action public static SetExploreMode(status: Opt<boolean>) {
        this._explore = status;
    }

    addDocTab = NewLightboxView.AddDocTab;

    @computed public static get ExploreMode() {
        return this._explore;
    }

    @computed public static get SidebarStatus() {
        return this._sidebarStatus;
    }
    @computed get leftBorder() {
        return Math.min(this.props.PanelWidth / 4, this.props.maxBorder[0]);
    }
    @computed get topBorder() {
        return Math.min(this.props.PanelHeight / 4, this.props.maxBorder[1]);
    }

    @computed
    get documentView() {
        const lightboxDoc = DocumentView.LightboxDoc();
        if (!lightboxDoc) return null;
        return (
            <GestureOverlay isActive>
                <DocumentView
                    ref={action((r: DocumentView | null) => {
                        NewLightboxView._docView = r !== null ? r : undefined;
                    })}
                    Document={lightboxDoc}
                    PanelWidth={this.newLightboxWidth}
                    PanelHeight={this.newLightboxHeight}
                    LayoutTemplate={NewLightboxView.LightboxDocTemplate}
                    isDocumentActive={returnTrue} // without this being true, sidebar annotations need to be activated before text can be selected.
                    isContentActive={returnTrue}
                    styleProvider={DefaultStyleProvider}
                    ScreenToLocalTransform={this.newLightboxScreenToLocal}
                    renderDepth={0}
                    containerViewPath={returnEmptyDoclist}
                    childFilters={this.docFilters}
                    childFiltersByRanges={returnEmptyFilter}
                    searchFilterDocs={returnEmptyDoclist}
                    addDocument={undefined}
                    removeDocument={undefined}
                    whenChildContentsActiveChanged={emptyFunction}
                    addDocTab={this.addDocTab}
                    pinToPres={DocumentView.PinDoc}
                    focus={emptyFunction}
                />
            </GestureOverlay>
        );
    }
    newLightboxWidth = () => this.props.PanelWidth - 420;
    newLightboxHeight = () => this.props.PanelHeight - 140;
    newLightboxScreenToLocal = () => new Transform(-this.leftBorder, -this.topBorder, 1);

    docFilters = () => NewLightboxView._docFilters || [];

    render() {
        const newLightboxHeaderHeight = 100;
        let downx = 0;
        let downy = 0;
        return !DocumentView.LightboxDoc() ? null : (
            <div
                className="newLightboxView-frame"
                onPointerDown={e => {
                    downx = e.clientX;
                    downy = e.clientY;
                }}
                onClick={e => {
                    if (Math.abs(downx - e.clientX) < 4 && Math.abs(downy - e.clientY) < 4) {
                        NewLightboxView.SetNewLightboxDoc(undefined);
                    }
                }}>
                <div className="app-document" style={{ gridTemplateColumns: `calc(100% - 400px) 400px` }}>
                    <div
                        className="newLightboxView-contents"
                        style={{
                            top: 20,
                            left: 20,
                            width: this.newLightboxWidth(),
                            height: this.newLightboxHeight() - 40,
                        }}>
                        <NewLightboxHeader height={newLightboxHeaderHeight} width={this.newLightboxWidth()} />
                        {!NewLightboxView._explore ? (
                            <div className="newLightboxView-doc" style={{ height: this.newLightboxHeight() }}>
                                {this.documentView}
                            </div>
                        ) : (
                            <div className="explore">
                                <ExploreView recs={NewLightboxView.Recs} bounds={NewLightboxView.Bounds} />
                            </div>
                        )}
                    </div>
                    <RecommendationList keywords={NewLightboxView.Keywords} />
                </div>
            </div>
        );
    }
}
interface NewLightboxTourBtnProps {
    navBtn: (left: Opt<string | number>, bottom: Opt<number>, top: number, icon: string, display: () => string, click: (e: React.MouseEvent) => void, color?: string) => JSX.Element;
    // eslint-disable-next-line react/no-unused-prop-types
    future: () => Opt<Doc[]>;
    stepInto: () => void;
}
@observer
export class NewLightboxTourBtn extends React.Component<NewLightboxTourBtnProps> {
    render() {
        return this.props.navBtn(
            '50%',
            0,
            0,
            'chevron-down',
            () => (DocumentView.LightboxDoc() /* && this.props.future()?.length */ ? '' : 'none'),
            e => {
                e.stopPropagation();
                this.props.stepInto();
            },
            ''
        );
    }
}
