import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@mui/material';
import { action, computed, makeObservable, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { emptyFunction, returnFalse, setupMoveUpEvents, simulateMouseClick } from '../../Utils';
import { Doc } from '../../fields/Doc';
import { RichTextField } from '../../fields/RichTextField';
import { Cast, DocCast } from '../../fields/Types';
import { DocUtils } from '../documents/Documents';
import { DragManager } from '../util/DragManager';
import { IsFollowLinkScript } from '../util/LinkFollower';
import { SelectionManager } from '../util/SelectionManager';
import { SharingManager } from '../util/SharingManager';
import { UndoManager, undoBatch } from '../util/UndoManager';
import './DocumentButtonBar.scss';
import { ObservableReactComponent } from './ObservableReactComponent';
import { TabDocView } from './collections/TabDocView';
import { Colors } from './global/globalEnums';
import { LinkPopup } from './linking/LinkPopup';
import { DocumentLinksButton } from './nodes/DocumentLinksButton';
import { DocumentView, DocumentViewInternal, OpenWhere } from './nodes/DocumentView';
import { DashFieldView } from './nodes/formattedText/DashFieldView';
import { PinProps } from './nodes/trails';
// import * as higflyout from '@hig/flyout';
// export const { anchorPoints } = higflyout;
// export const Flyout = higflyout.default;

const cloud: IconProp = 'cloud-upload-alt';
const fetch: IconProp = 'sync-alt';

enum UtilityButtonState {
    Default,
    OpenRight,
    OpenExternally,
}

@observer
export class DocumentButtonBar extends ObservableReactComponent<{ views: () => (DocumentView | undefined)[]; stack?: any }> {
    private _dragRef = React.createRef<HTMLDivElement>();
    private _pullAnimating = false;
    private _pushAnimating = false;
    private _pullColorAnimating = false;
    @observable private pushIcon: IconProp = 'arrow-alt-circle-up';
    @observable private pullIcon: IconProp = 'arrow-alt-circle-down';
    @observable private pullColor: string = 'white';
    @observable public isAnimatingFetch = false;
    @observable public isAnimatingPulse = false;

    @observable private openHover: UtilityButtonState = UtilityButtonState.Default;

    @observable public static Instance: DocumentButtonBar;
    public static hasPushedHack = false;
    public static hasPulledHack = false;

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

    public startPullOutcome = action((success: boolean) => {
        if (!this._pullAnimating) {
            this._pullAnimating = true;
            this.pullIcon = success ? 'check-circle' : 'stop-circle';
            setTimeout(
                () =>
                    runInAction(() => {
                        this.pullIcon = 'arrow-alt-circle-down';
                        this._pullAnimating = false;
                    }),
                1000
            );
        }
    });

    public startPushOutcome = action((success: boolean) => {
        this.isAnimatingPulse = false;
        if (!this._pushAnimating) {
            this._pushAnimating = true;
            this.pushIcon = success ? 'check-circle' : 'stop-circle';
            setTimeout(
                () =>
                    runInAction(() => {
                        this.pushIcon = 'arrow-alt-circle-up';
                        this._pushAnimating = false;
                    }),
                1000
            );
        }
    });

    public setPullState = action((unchanged: boolean) => {
        this.isAnimatingFetch = false;
        if (!this._pullColorAnimating) {
            this._pullColorAnimating = true;
            this.pullColor = unchanged ? 'lawngreen' : 'red';
            setTimeout(this.clearPullColor, 1000);
        }
    });

    private clearPullColor = action(() => {
        this.pullColor = 'white';
        this._pullColorAnimating = false;
    });

    get view0() {
        return this._props.views()?.[0];
    }

    @observable subFollow = '';
    @computed
    get followLinkButton() {
        const targetDoc = this.view0?.Document;
        const followBtn = (allDocs: boolean, click: (doc: Doc) => void, isSet: (doc?: Doc) => boolean, icon: IconProp) => {
            const tooltip = `Follow ${this.subPin}documents`;
            return !tooltip ? null : (
                <Tooltip title={<div className="dash-tooltip">{tooltip}</div>}>
                    <div className="documentButtonBar-followIcon" style={{ backgroundColor: isSet(targetDoc) ? Colors.LIGHT_BLUE : Colors.DARK_GRAY, color: isSet(targetDoc) ? Colors.BLACK : Colors.WHITE }}>
                        <FontAwesomeIcon
                            className="documentdecorations-icon"
                            style={{ width: 20 }}
                            key={icon.toString()}
                            size="sm"
                            icon={icon}
                            onPointerEnter={action(e => (this.subPin = allDocs ? 'All ' : ''))}
                            onPointerLeave={action(e => (this.subPin = ''))}
                            onClick={e => {
                                this._props.views().forEach(dv => click(dv!.Document));
                                e.stopPropagation();
                            }}
                        />
                    </div>
                </Tooltip>
            );
        };
        const followLink = IsFollowLinkScript(targetDoc?.onClick);
        return !targetDoc ? null : (
            <Tooltip title={<div className="dash-tooltip">Set onClick to follow primary link</div>}>
                <div
                    className="documentButtonBar-icon documentButtonBar-follow"
                    style={{ backgroundColor: followLink ? Colors.LIGHT_BLUE : Colors.DARK_GRAY, color: followLink ? Colors.BLACK : Colors.WHITE }}
                    onClick={undoBatch(e => this._props.views().map(view => view?.docView?.toggleFollowLink(undefined, false)))}>
                    <div className="documentButtonBar-followTypes">
                        {followBtn(
                            true,
                            (doc: Doc) => (doc.followAllLinks = !doc.followAllLinks),
                            (doc?: Doc) => (doc?.followAllLinks ? true : false),
                            'window-maximize'
                        )}
                    </div>
                    <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="hand-point-right" />
                </div>
            </Tooltip>
        );
    }

    @observable subLink = '';
    @computed get linkButton() {
        const targetDoc = this.view0?.Document;
        return !targetDoc || !this.view0 ? null : (
            <div className="documentButtonBar-icon documentButtonBar-link">
                <div className="documentButtonBar-linkTypes">
                    <Tooltip title={<div>search for target</div>}>
                        <div className="documentButtonBar-button">
                            <button style={{ backgroundColor: 'transparent', width: 35, height: 35, display: 'flex', justifyContent: 'center', alignItems: 'center', position: 'relative' }} onPointerDown={this.toggleLinkSearch}>
                                <FontAwesomeIcon style={{ position: 'absolute', transform: 'scale(1.5)' }} icon={'search'} size="lg" />
                                <FontAwesomeIcon style={{ position: 'absolute', transform: 'scale(0.5)', transformOrigin: 'center', top: 9, left: 2 }} icon={'link'} size="lg" />
                            </button>
                        </div>
                    </Tooltip>
                    <Tooltip title={<div>open linked trail</div>}>
                        <div className="documentButtonBar-button">
                            <button style={{ backgroundColor: 'transparent', width: 35, height: 35, display: 'flex', justifyContent: 'center', alignItems: 'center', position: 'relative' }} onPointerDown={this.toggleTrail}>
                                <FontAwesomeIcon icon="taxi" size="lg" />
                            </button>
                        </div>
                    </Tooltip>
                </div>
                <div style={{ width: 25, height: 25 }}>
                    <DocumentLinksButton View={this.view0} AlwaysOn={true} InMenu={true} StartLink={true} />
                </div>
            </div>
        );
    }
    @observable subEndLink = '';
    @computed
    get endLinkButton() {
        const linkBtn = (pinLayout: boolean, pinContent: boolean, icon: IconProp) => {
            const tooltip = `Finish Link and Save ${this.subEndLink} data`;
            return !this.view0 ? null : (
                <Tooltip title={<div className="dash-tooltip">{tooltip}</div>}>
                    <div className="documentButtonBar-pinIcon">
                        <FontAwesomeIcon
                            className="documentdecorations-icon"
                            style={{ width: 20 }}
                            key={icon.toString()}
                            size="sm"
                            icon={icon}
                            onPointerEnter={action(e => (this.subEndLink = (pinLayout ? 'Layout' : '') + (pinLayout && pinContent ? ' &' : '') + (pinContent ? ' Content' : '')))}
                            onPointerLeave={action(e => (this.subEndLink = ''))}
                            onClick={e => {
                                this.view0 &&
                                    DocumentLinksButton.finishLinkClick(e.clientX, e.clientY, DocumentLinksButton.StartLink, this.view0.Document, true, this.view0, {
                                        pinDocLayout: pinLayout,
                                        pinData: !pinContent ? {} : { poslayoutview: true, dataannos: true, dataview: pinContent },
                                    } as PinProps);

                                e.stopPropagation();
                            }}
                        />
                    </div>
                </Tooltip>
            );
        };
        return !this.view0 ? null : (
            <div className="documentButtonBar-icon documentButtonBar-pin">
                <div className="documentButtonBar-pinTypes">
                    {linkBtn(true, false, 'window-maximize')}
                    {linkBtn(false, true, 'address-card')}
                    {linkBtn(true, true, 'id-card')}
                </div>
                <DocumentLinksButton View={this.view0} AlwaysOn={true} InMenu={true} StartLink={false} />
            </div>
        );
    }

    @observable subPin = '';
    @computed
    get pinButton() {
        const targetDoc = this.view0?.Document;
        const pinBtn = (pinLayoutView: boolean, pinContentView: boolean, icon: IconProp) => {
            const tooltip = `Pin Document and Save ${this.subPin} to trail`;
            return !tooltip ? null : (
                <Tooltip title={<div className="dash-tooltip">{tooltip}</div>}>
                    <div className="documentButtonBar-pinIcon">
                        <FontAwesomeIcon
                            className="documentdecorations-icon"
                            style={{ width: 20 }}
                            key={icon.toString()}
                            size="sm"
                            icon={icon}
                            onPointerEnter={action(
                                e =>
                                    (this.subPin =
                                        (pinLayoutView ? 'Layout' : '') +
                                        (pinLayoutView && pinContentView ? ' &' : '') +
                                        (pinContentView ? ' Content View' : '') +
                                        (pinLayoutView && pinContentView ? '(shift+alt)' : pinLayoutView ? '(shift)' : pinContentView ? '(alt)' : ''))
                            )}
                            onPointerLeave={action(e => (this.subPin = ''))}
                            onClick={e => {
                                const docs = this._props
                                    .views()
                                    .filter(v => v)
                                    .map(dv => dv!.Document);
                                TabDocView.PinDoc(docs, {
                                    pinAudioPlay: true,
                                    pinDocLayout: pinLayoutView,
                                    pinData: { dataview: pinContentView },
                                    activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null),
                                    currentFrame: Cast(docs.lastElement()?.currentFrame, 'number', null),
                                });
                                e.stopPropagation();
                            }}
                        />
                    </div>
                </Tooltip>
            );
        };
        return !targetDoc ? null : (
            <Tooltip title={<div className="dash-tooltip">{`Pin Document ${SelectionManager.Views.length > 1 ? 'multiple documents' : ''} to Trail`}</div>}>
                <div
                    className="documentButtonBar-icon documentButtonBar-pin"
                    onClick={e => {
                        const docs = this._props
                            .views()
                            .filter(v => v)
                            .map(dv => dv!.Document);
                        TabDocView.PinDoc(docs, { pinAudioPlay: true, pinDocLayout: e.shiftKey, pinData: { dataview: e.altKey }, activeFrame: Cast(docs.lastElement()?.activeFrame, 'number', null) });
                        e.stopPropagation();
                    }}>
                    <div className="documentButtonBar-pinTypes">
                        {pinBtn(true, false, 'window-maximize')}
                        {pinBtn(false, true, 'address-card')}
                        {pinBtn(true, true, 'id-card')}
                    </div>
                    <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="map-pin" />
                </div>
            </Tooltip>
        );
    }

    @computed
    get shareButton() {
        const targetDoc = this.view0?.Document;
        return !targetDoc ? null : (
            <Tooltip title={<div className="dash-tooltip">{'Open Sharing Manager'}</div>}>
                <div className="documentButtonBar-icon" style={{ color: 'white' }} onClick={e => SharingManager.Instance.open(this.view0, targetDoc)}>
                    <FontAwesomeIcon className="documentdecorations-icon" icon="users" />
                </div>
            </Tooltip>
        );
    }

    @computed
    get menuButton() {
        const targetDoc = this.view0?.Document;
        return !targetDoc ? null : (
            <Tooltip title={<div className="dash-tooltip">{`Open Context Menu`}</div>}>
                <div className="documentButtonBar-icon" style={{ color: 'white', cursor: 'pointer' }} onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, e => this.openContextMenu(e))}>
                    <FontAwesomeIcon className="documentdecorations-icon" icon="bars" />
                </div>
            </Tooltip>
        );
    }
    @computed
    get metadataButton() {
        const view0 = this.view0;
        return !view0 ? null : (
            <Tooltip title={<div className="dash-tooltip">Show metadata panel</div>}>
                <div className="documentButtonBar-linkFlyout">
                    {/* <Flyout
                        anchorPoint={anchorPoints.LEFT_TOP}
                        content={
                            <MetadataEntryMenu
                                docs={this._props
                                    .views()
                                    .filter(dv => dv)
                                    .map(dv => dv!.Document)}
                                suggestWithFunction
                            /> // tfs: @bcz This might need to be the data document?
                        }>
                        <div className={'documentButtonBar-linkButton-' + 'empty'} onPointerDown={e => e.stopPropagation()}>
                            {<FontAwesomeIcon className="documentdecorations-icon" icon="tag" />}
                        </div>
                    </Flyout> */}
                </div>
            </Tooltip>
        );
    }

    @observable _isRecording = false;
    _stopFunc: () => void = emptyFunction;
    @computed
    get recordButton() {
        const targetDoc = this.view0?.Document;
        return !targetDoc ? null : (
            <Tooltip title={<div className="dash-tooltip">Press to record audio annotation</div>}>
                <div
                    className="documentButtonBar-icon"
                    style={{ backgroundColor: this._isRecording ? Colors.ERROR_RED : Colors.DARK_GRAY, color: Colors.WHITE }}
                    onPointerDown={action((e: React.PointerEvent) => {
                        this._isRecording = true;
                        this._props.views().map(view => view && DocumentViewInternal.recordAudioAnnotation(view.dataDoc, view.LayoutFieldKey, stopFunc => (this._stopFunc = stopFunc), emptyFunction));
                        const b = UndoManager.StartBatch('Recording');
                        setupMoveUpEvents(
                            this,
                            e,
                            returnFalse,
                            action(() => {
                                this._isRecording = false;
                                this._stopFunc();
                                b.end();
                            }),
                            emptyFunction
                        );
                    })}>
                    <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="microphone" />
                </div>
            </Tooltip>
        );
    }
    @observable _embedDown = false;
    onTemplateButton = action((e: React.PointerEvent): void => {
        this._tooltipOpen = false;
        setupMoveUpEvents(this, e, this.onEmbedButtonMoved, emptyFunction, emptyFunction);
    });
    onEmbedButtonMoved = () => {
        if (this._dragRef.current) {
            const dragDocView = this.view0!;
            const dragData = new DragManager.DocumentDragData([dragDocView.Document]);
            const [left, top] = dragDocView._props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
            dragData.defaultDropAction = 'embed';
            dragData.canEmbed = true;
            DragManager.StartDocumentDrag([dragDocView.ContentDiv!], dragData, left, top, { hideSource: false });
            return true;
        }
        return false;
    };

    _ref = React.createRef<HTMLDivElement>();
    @observable _tooltipOpen: boolean = false;
    @computed
    get templateButton() {
        const view0 = this.view0;
        const views = this._props.views();
        return !view0 ? null : (
            <Tooltip title={<div className="dash-tooltip">Tap to Customize Layout. Drag an embedding</div>} open={this._tooltipOpen} onClose={action(() => (this._tooltipOpen = false))} placement="bottom">
                <div className="documentButtonBar-linkFlyout" ref={this._dragRef} onPointerEnter={action(() => !this._ref.current?.getBoundingClientRect().width && (this._tooltipOpen = true))}>
                    {/* <Flyout
                        anchorPoint={anchorPoints.LEFT_TOP}
                        onOpen={action(() => (this._embedDown = true))}
                        onClose={action(() => (this._embedDown = false))}
                        content={
                            !this._embedDown ? null : (
                                <div ref={this._ref}>
                                    {' '}
                                    <TemplateMenu docViews={views.filter(v => v).map(v => v as DocumentView)} />
                                </div>
                            )
                        }>
                        <div className={'documentButtonBar-linkButton-empty'} ref={this._dragRef} onPointerDown={this.onTemplateButton}>
                            <FontAwesomeIcon className="documentdecorations-icon" icon="edit" size="sm" />
                        </div>
                    </Flyout> */}
                </div>
            </Tooltip>
        );
    }

    openContextMenu = (e: PointerEvent) => {
        let child = SelectionManager.Views[0].ContentDiv!.children[0];
        while (child.children.length) {
            const next = Array.from(child.children).find(c => c.className?.toString().includes('SVGAnimatedString') || typeof c.className === 'string');
            if (next?.className?.toString().includes(DocumentView.ROOT_DIV)) break;
            if (next?.className?.toString().includes(DashFieldView.name)) break;
            if (next) child = next;
            else break;
        }
        simulateMouseClick(child, e.clientX, e.clientY - 30, e.screenX, e.screenY - 30);
    };

    @observable _showLinkPopup = false;
    @action
    toggleLinkSearch = (e: React.PointerEvent) => {
        this._showLinkPopup = !this._showLinkPopup;
        e.stopPropagation();
    };

    @observable _captureEndLinkLayout = false;
    @action
    captureEndLinkLayout = (e: React.PointerEvent) => {
        this._captureEndLinkLayout = !this._captureEndLinkLayout;
    };
    @observable _captureEndLinkContent = false;
    @action
    captureEndLinkContent = (e: React.PointerEvent) => {
        this._captureEndLinkContent = !this._captureEndLinkContent;
    };

    @action
    captureEndLinkState = (e: React.PointerEvent) => {
        this._captureEndLinkContent = this._captureEndLinkLayout = !this._captureEndLinkLayout;
    };

    @action
    toggleTrail = (e: React.PointerEvent) => {
        const rootView = this._props.views()[0];
        const doc = rootView?.Document;
        if (doc) {
            const anchor = rootView.ComponentView?.getAnchor?.(true) ?? doc;
            const trail = DocCast(anchor.presentationTrail) ?? Doc.MakeCopy(DocCast(Doc.UserDoc().emptyTrail), true);
            if (trail !== anchor.presentationTrail) {
                DocUtils.MakeLink(anchor, trail, { link_relationship: 'link trail' });
                anchor.presentationTrail = trail;
            }
            Doc.ActivePresentation = trail;
            this._props.views().lastElement()?._props.addDocTab(trail, OpenWhere.replaceRight);
        }
        e.stopPropagation();
    };
    render() {
        const doc = this.view0?.Document;
        if (!doc || !this.view0) return null;

        const isText = () => doc[this.view0!.LayoutFieldKey] instanceof RichTextField;
        return (
            <div className="documentButtonBar">
                <div className="documentButtonBar-button">
                    <DocumentLinksButton View={this.view0} AlwaysOn={true} InMenu={true} ShowCount={true} />
                </div>
                {this._showLinkPopup ? (
                    <div style={{ position: 'absolute', zIndex: 1000 }}>
                        <LinkPopup
                            key="popup"
                            linkCreated={link => (link.link_displayLine = !IsFollowLinkScript(this._props.views().lastElement()?.Document.onClick))}
                            linkCreateAnchor={() => this._props.views().lastElement()?.ComponentView?.getAnchor?.(true)}
                            linkFrom={() => this._props.views().lastElement()?.Document}
                        />
                    </div>
                ) : (
                    <div className="documentButtonBar-button">{this.linkButton}</div>
                )}

                {DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== doc ? <div className="documentButtonBar-button">{this.endLinkButton} </div> : null}
                {
                    Doc.noviceMode ? null : <div className="documentButtonBar-button">{this.templateButton}</div>
                    /*<div className="documentButtonBar-button"> {this.metadataButton} </div> */
                }
                {!SelectionManager.Views?.some(v => v.allLinks.length) ? null : <div className="documentButtonBar-button">{this.followLinkButton}</div>}
                <div className="documentButtonBar-button">{this.pinButton}</div>
                <div className="documentButtonBar-button">{this.recordButton}</div>
                {!Doc.UserDoc()['documentLinksButton-fullMenu'] ? null : <div className="documentButtonBar-button">{this.shareButton}</div>}
                <div className="documentButtonBar-button">{this.menuButton}</div>
            </div>
        );
    }
}
