import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Toggle, ToggleType, Type } from 'browndash-components';
import { action, computed, makeObservable, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc, DocListCast, FieldResult, Opt } from '../../fields/Doc';
import { InkTool } from '../../fields/InkField';
import { Cast, NumCast } from '../../fields/Types';
import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, Utils } from '../../Utils';
import { DocUtils } from '../documents/Documents';
import { DocumentManager } from '../util/DocumentManager';
import { LinkManager } from '../util/LinkManager';
import { SelectionManager } from '../util/SelectionManager';
import { SettingsManager } from '../util/SettingsManager';
import { Transform } from '../util/Transform';
import { CollectionDockingView } from './collections/CollectionDockingView';
import { CollectionStackedTimeline } from './collections/CollectionStackedTimeline';
import { TabDocView } from './collections/TabDocView';
import { GestureOverlay } from './GestureOverlay';
import './LightboxView.scss';
import { DocumentView, OpenWhere, OpenWhereMod } from './nodes/DocumentView';
import { DefaultStyleProvider, wavyBorderPath } from './StyleProvider';
import { ObservableReactComponent } from './ObservableReactComponent';
import { SnappingManager } from '../util/SnappingManager';

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

const savedKeys = ['freeform_panX', 'freeform_panY', 'freeform_scale', 'layout_scrollTop', 'layout_fieldKey'];
type LightboxSavedState = { [key: string]: FieldResult; }; // prettier-ignore
@observer
export class LightboxView extends ObservableReactComponent<LightboxViewProps> {
    public static Contains(view?:DocumentView) { return view && LightboxView.Instance?._docView&&  (view.containerViewPath?.() ?? []).concat(view).includes(LightboxView.Instance?._docView); } // prettier-ignore
    public static get LightboxDoc() { return LightboxView.Instance?._doc; } // prettier-ignore
    static Instance: LightboxView;
    private _path: {
        doc: Opt<Doc>; //
        target: Opt<Doc>;
        history: { doc: Doc; target?: Doc }[];
        future: Doc[];
        saved: LightboxSavedState;
    }[] = [];
    private _savedState: LightboxSavedState = {};
    private _history: { doc: Doc; target?: Doc }[] = [];
    @observable private _future: Doc[] = [];
    @observable private _layoutTemplate: Opt<Doc> = undefined;
    @observable private _layoutTemplateString: Opt<string> = undefined;
    @observable private _doc: Opt<Doc> = undefined;
    @observable private _docTarget: Opt<Doc> = undefined;
    @observable private _docView: Opt<DocumentView> = undefined;

    @computed get leftBorder() { return Math.min(this._props.PanelWidth / 4, this._props.maxBorder[0]); } // prettier-ignore
    @computed get topBorder()  { return Math.min(this._props.PanelHeight / 4, this._props.maxBorder[1]); } // prettier-ignore

    constructor(props: any) {
        super(props);
        makeObservable(this);
        LightboxView.Instance = this;
    }

    @action
    public SetLightboxDoc(doc: Opt<Doc>, target?: Doc, future?: Doc[], layoutTemplate?: Doc | string) {
        const lightDoc = this._doc;
        lightDoc && lightDoc !== doc && savedKeys.forEach(key => (lightDoc[key] = this._savedState[key]));
        this._savedState = {};

        if (doc) {
            lightDoc !== doc && savedKeys.map(key => (this._savedState[key] = Doc.Get(doc, key, true)));
            const l = DocUtils.MakeLinkToActiveAudio(() => doc).lastElement();
            l && (Cast(l.link_anchor_2, Doc, null).backgroundColor = 'lightgreen');
            CollectionStackedTimeline.CurrentlyPlaying?.forEach(dv => dv.ComponentView?.Pause?.());
            this._history.push({ doc, target });
        } else {
            this._future = [];
            this._history = [];
            Doc.ActiveTool = InkTool.None;
            SnappingManager.SetExploreMode(false);
        }
        SelectionManager.DeselectAll();
        if (future) {
            this._future.push(
                ...(this._doc ? [this._doc] : []),
                ...future
                    .slice()
                    .sort((a, b) => NumCast(b._timecodeToShow) - NumCast(a._timecodeToShow))
                    .sort((a, b) => LinkManager.Links(a).length - LinkManager.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 AddDocTab = (doc: Doc, location: OpenWhere, layoutTemplate?: Doc | string) =>
        this.SetLightboxDoc(
            doc,
            undefined,
            [...DocListCast(doc[Doc.LayoutFieldKey(doc)]), ...DocListCast(doc[Doc.LayoutFieldKey(doc) + '_annotations']).filter(anno => anno.annotationOn !== doc), ...this._future].sort(
                (a, b) => NumCast(b._timecodeToShow) - NumCast(a._timecodeToShow)
            ),
            layoutTemplate
        );
    @action
    next = () => {
        const lightDoc = this._doc;
        if (!lightDoc) return;
        const target = (this._docTarget = this._future.pop());
        const targetDocView = target && DocumentManager.Instance.getLightboxDocumentView(target);
        if (targetDocView && target) {
            const l = DocUtils.MakeLinkToActiveAudio(() => targetDocView.ComponentView?.getAnchor?.(true) || target).lastElement();
            l && (Cast(l.link_anchor_2, Doc, null).backgroundColor = 'lightgreen');
            DocumentManager.Instance.showDocument(target, { willZoomCentered: true, zoomScale: 0.9 });
            if (this._history.lastElement().target !== target) this._history.push({ doc: lightDoc, target });
        } else if (!target && this._path.length) {
            savedKeys.forEach(key => (lightDoc[key] = this._savedState[key]));
            this._path.pop();
        } else {
            this.SetLightboxDoc(target);
        }
    };
    @action
    previous = () => {
        const previous = this._history.pop();
        if (!previous || !this._history.length) {
            this.SetLightboxDoc(undefined);
            return;
        }
        const { doc, target } = this._history.lastElement();
        const docView = DocumentManager.Instance.getLightboxDocumentView(target || doc);
        if (docView) {
            this._docTarget = target;
            target && DocumentManager.Instance.showDocument(target, { willZoomCentered: true, zoomScale: 0.9 });
        } else {
            this.SetLightboxDoc(doc, target);
        }
        if (this._future.lastElement() !== previous.target || previous.doc) this._future.push(previous.target || previous.doc);
    };
    @action
    stepInto = () => {
        this._path.push({
            doc: this._doc,
            target: this._docTarget,
            future: this._future,
            history: this._history,
            saved: this._savedState,
        });
        if (this._docTarget) {
            const fieldKey = Doc.LayoutFieldKey(this._docTarget);
            const contents = [...DocListCast(this._docTarget[fieldKey]), ...DocListCast(this._docTarget[fieldKey + '_annotations'])];
            const links = LinkManager.Links(this._docTarget)
                .map(link => LinkManager.getOppositeAnchor(link, this._docTarget!)!)
                .filter(doc => doc);
            this.SetLightboxDoc(this._docTarget, undefined, contents.length ? contents : links);
        }
    };

    downloadDoc = () => {
        const lightDoc = this._docTarget ?? this._doc;
        if (lightDoc) {
            Doc.RemoveDocFromList(Doc.MyRecentlyClosed, 'data', lightDoc);
            CollectionDockingView.AddSplit(lightDoc, OpenWhereMod.none);
            this.SetLightboxDoc(undefined);
        }
    };
    toggleFitWidth = () => this._doc && (this._doc._layout_fitWidth = !this._doc._layout_fitWidth);
    togglePen = () => (Doc.ActiveTool = Doc.ActiveTool === InkTool.Pen ? InkTool.None : InkTool.Pen);
    toggleExplore = () => SnappingManager.SetExploreMode(!SnappingManager.ExploreMode);

    lightboxDoc = () => this._doc;
    lightboxWidth = () => this._props.PanelWidth - this.leftBorder * 2;
    lightboxHeight = () => this._props.PanelHeight - this.topBorder * 2;
    lightboxScreenToLocal = () => new Transform(-this.leftBorder, -this.topBorder, 1);
    lightboxDocTemplate = () => this._layoutTemplate;
    future = () => this._future;

    renderNavBtn = (left: Opt<string | number>, bottom: Opt<number>, top: number, icon: IconProp, display: any, click: () => void, color?: string) => {
        return (
            <div
                className="lightboxView-navBtn-frame"
                style={{
                    display: display ? '' : 'none',
                    left,
                    width: bottom !== undefined ? undefined : Math.min(this._props.PanelWidth / 4, this._props.maxBorder[0]),
                    bottom,
                }}>
                <div
                    className="lightboxView-navBtn"
                    title={color}
                    style={{ top, color: SettingsManager.userColor, background: undefined }}
                    onClick={e => {
                        e.stopPropagation();
                        click();
                    }}>
                    <div style={{ height: 10 }}>{color}</div>
                    <FontAwesomeIcon icon={icon} size="3x" />
                </div>
            </div>
        );
    };
    render() {
        let downx = 0,
            downy = 0;
        const toggleBtn = (classname: string, tooltip: string, toggleBackground: any, icon: IconProp, icon2: IconProp | string, onClick: () => void) => (
            <div className={classname}>
                <Toggle
                    tooltip={tooltip}
                    color={SettingsManager.userColor}
                    background={toggleBackground ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor}
                    toggleType={ToggleType.BUTTON}
                    type={Type.TERT}
                    icon={<FontAwesomeIcon icon={toggleBackground ? icon : (icon2 as IconProp) || icon} size="sm" />}
                    onClick={e => {
                        e.stopPropagation();
                        runInAction(onClick);
                    }}
                />
            </div>
        );
        return !this._doc ? null : (
            <div
                className="lightboxView-frame"
                style={{ background: SettingsManager.userBackgroundColor }}
                onPointerDown={e => {
                    downx = e.clientX;
                    downy = e.clientY;
                }}
                onClick={e => Utils.isClick(e.clientX, e.clientY, downx, downy, Date.now()) && this.SetLightboxDoc(undefined)}>
                <div
                    className="lightboxView-contents"
                    style={{
                        left: this.leftBorder,
                        top: this.topBorder,
                        width: this.lightboxWidth(),
                        height: this.lightboxHeight(),
                        clipPath: `path('${Doc.UserDoc().renderStyle === 'comic' ? wavyBorderPath(this.lightboxWidth(), this.lightboxHeight()) : undefined}')`,
                        background: SettingsManager.userBackgroundColor,
                        color: SettingsManager.userColor,
                    }}>
                    <GestureOverlay isActive={true}>
                        <DocumentView
                            ref={action((r: DocumentView | null) => (this._docView = r !== null ? r : undefined))}
                            Document={this._doc}
                            PanelWidth={this.lightboxWidth}
                            PanelHeight={this.lightboxHeight}
                            LayoutTemplate={this.lightboxDocTemplate}
                            isDocumentActive={returnTrue} // without this being true, sidebar annotations need to be activated before text can be selected.
                            isContentActive={returnTrue}
                            styleProvider={DefaultStyleProvider}
                            ScreenToLocalTransform={this.lightboxScreenToLocal}
                            renderDepth={0}
                            containerViewPath={returnEmptyDoclist}
                            childFilters={returnEmptyFilter}
                            childFiltersByRanges={returnEmptyFilter}
                            searchFilterDocs={returnEmptyDoclist}
                            addDocument={undefined}
                            removeDocument={undefined}
                            whenChildContentsActiveChanged={emptyFunction}
                            addDocTab={this.AddDocTab}
                            pinToPres={TabDocView.PinDoc}
                            bringToFront={emptyFunction}
                            onBrowseClickScript={DocumentView.exploreMode}
                            focus={emptyFunction}
                        />
                    </GestureOverlay>
                </div>

                {this.renderNavBtn(0, undefined, this._props.PanelHeight / 2 - 12.5, 'chevron-left', this._doc && this._history.length, this.previous)}
                {this.renderNavBtn(
                    this._props.PanelWidth - Math.min(this._props.PanelWidth / 4, this._props.maxBorder[0]),
                    undefined,
                    this._props.PanelHeight / 2 - 12.5,
                    'chevron-right',
                    this._doc && this._future.length,
                    this.next,
                    this.future().length.toString()
                )}
                <LightboxTourBtn lightboxDoc={this.lightboxDoc} navBtn={this.renderNavBtn} future={this.future} stepInto={this.stepInto} />
                {toggleBtn('lightboxView-navBtn', 'toggle reading view', this._doc?._layout_fitWidth, 'book-open', 'book', this.toggleFitWidth)}
                {toggleBtn('lightboxView-tabBtn', 'open document in a tab', false, 'file-download', '', this.downloadDoc)}
                {toggleBtn('lightboxView-penBtn', 'toggle pen annotation', Doc.ActiveTool === InkTool.Pen, 'pen', '', this.togglePen)}
                {toggleBtn('lightboxView-exploreBtn', 'toggle navigate only mode', SnappingManager.ExploreMode, 'globe-americas', '', this.toggleExplore)}
            </div>
        );
    }
}
interface LightboxTourBtnProps {
    navBtn: (left: Opt<string | number>, bottom: Opt<number>, top: number, icon: IconProp, display: any, click: () => void, color?: string) => JSX.Element;
    future: () => Opt<Doc[]>;
    stepInto: () => void;
    lightboxDoc: () => Opt<Doc>;
}
@observer
export class LightboxTourBtn extends React.Component<LightboxTourBtnProps> {
    render() {
        return this.props.navBtn('50%', 0, 0, 'chevron-down', this.props.lightboxDoc(), this.props.stepInto, '');
    }
}
