import { IconLookup, IconProp } from '@fortawesome/fontawesome-svg-core';
import { faCalendarDays } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@mui/material';
import { Popup } from '@dash/components';
import { action, computed, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { FaEdit } from 'react-icons/fa';
import { returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick } from '../../ClientUtils';
import { emptyFunction } from '../../Utils';
import { Doc, DocListCast } from '../../fields/Doc';
import { Cast, DocCast } from '../../fields/Types';
import { DocUtils, IsFollowLinkScript } from '../documents/DocUtils';
import { CalendarManager } from '../util/CalendarManager';
import { DictationManager } from '../util/DictationManager';
import { DragManager } from '../util/DragManager';
import { dropActionType } from '../util/DropActionTypes';
import { SharingManager } from '../util/SharingManager';
import { UndoManager, undoable } from '../util/UndoManager';
import './DocumentButtonBar.scss';
import { ObservableReactComponent } from './ObservableReactComponent';
import { PinProps } from './PinFuncs';
import { TemplateMenu } from './TemplateMenu';
import { Colors } from './global/globalEnums';
import { LinkPopup } from './linking/LinkPopup';
import { DocumentLinksButton } from './nodes/DocumentLinksButton';
import { DocumentView } from './nodes/DocumentView';
import { OpenWhere } from './nodes/OpenWhere';
import { DashFieldView } from './nodes/formattedText/DashFieldView';

@observer
export class DocumentButtonBar extends ObservableReactComponent<{ views: () => (DocumentView | undefined)[]; stack?: unknown }> {
    private _dragRef = React.createRef<HTMLDivElement>();
    // eslint-disable-next-line no-use-before-define
    public static Instance: DocumentButtonBar;

    constructor(props: { views: () => (DocumentView | undefined)[]; stack?: unknown }) {
        super(props);
        makeObservable(this);
        DocumentButtonBar.Instance = this;
    }

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

    @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(() => {
                                this.subPin = allDocs ? 'All ' : '';
                            })}
                            onPointerLeave={action(() => {
                                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={undoable(() => this._props.views().map(view => view?.toggleFollowLink(undefined, false)), 'follow link')}>
                    <div className="documentButtonBar-followTypes">
                        {followBtn(
                            true,
                            (doc: Doc) => {
                                doc.followAllLinks = !doc.followAllLinks;
                            },
                            (doc?: Doc) => !!doc?.followAllLinks,
                            '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 type="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 type="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 InMenu StartLink />
                </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(() => {
                                this.subEndLink = (pinLayout ? 'Layout' : '') + (pinLayout && pinContent ? ' &' : '') + (pinContent ? ' Content' : '');
                            })}
                            onPointerLeave={action(() => {
                                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 InMenu 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(() => {
                                this.subPin =
                                    (pinLayoutView ? 'Layout' : '') +
                                    (pinLayoutView && pinContentView ? ' &' : '') +
                                    (pinContentView ? ' Content View' : '') +
                                    (pinLayoutView && pinContentView ? '(shift+alt)' : pinLayoutView ? '(shift)' : pinContentView ? '(alt)' : '');
                            })}
                            onPointerLeave={action(() => {
                                this.subPin = '';
                            })}
                            onClick={e => {
                                const docs = this._props
                                    .views()
                                    .filter(v => v)
                                    .map(dv => dv!.Document);
                                DocumentView.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 ${DocumentView.Selected().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);
                        DocumentView.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={() => 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, clickEv => this.openContextMenu(clickEv))}>
                    <FontAwesomeIcon className="documentdecorations-icon" icon="bars" />
                </div>
            </Tooltip>
        );
    }

    @computed
    get calendarButton() {
        const targetDoc = this.view0?.Document;
        return !targetDoc ? null : (
            <Tooltip title={<div className="dash-calendar-button">Open calendar menu</div>}>
                <div
                    className="documentButtonBar-icon"
                    style={{ color: 'white' }}
                    onClick={() => {
                        CalendarManager.Instance.open(this.view0, targetDoc);
                    }}>
                    <FontAwesomeIcon className="documentdecorations-icon" icon={faCalendarDays as IconLookup} />
                </div>
            </Tooltip>
        );
    }

    /**
     * Allows for both the keywords and the icon tags to be shown using a quasi- multitoggle
     */
    @computed
    get keywordButton() {
        const targetDoc = this.view0?.Document;

        return !targetDoc ? null : (
            <div className="documentButtonBar-icon">
                {/* <div className="documentButtonBar-pinTypes" style={{ width: '40px' }}>
                    {metaBtn('tags', 'star')}
                    {metaBtn('keywords', 'id-card')}
                </div> */}

                <Tooltip title={<div className="dash-keyword-button">Open keyword menu</div>}>
                    <div
                        className="documentButtonBar-icon"
                        style={{ color: 'white' }}
                        onClick={undoable(e => {
                            const showing = DocumentView.Selected().some(dv => dv.showTags);
                            DocumentView.Selected().forEach(dv => {
                                dv.layoutDoc._layout_showTags = !showing;
                                if (e.shiftKey)
                                    DocListCast(dv.Document[Doc.LayoutFieldKey(dv.Document) + '_annotations']).forEach(doc => {
                                        if (doc.face) doc.hidden = showing;
                                    });
                            });
                        }, 'show Doc tags')}>
                        <FontAwesomeIcon className="documentdecorations-icon" icon="tag" />
                    </div>
                </Tooltip>
            </div>
        );
    }

    @computed
    get aiEditorButton() {
        const targetDoc = this.view0?.Document;
        return !targetDoc ? null : (
            <Tooltip title={<div className="dash-ai-editor-button">Edit with AI</div>}>
                <div className="documentButtonBar-icon" style={{ color: 'white' }} onClick={undoable(() => this.view0?.toggleAIEditor(), 'toggle AI editor')}>
                    <FontAwesomeIcon className="documentdecorations-icon" icon="robot" />
                </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 &&
                                DictationManager.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 origin = dragDocView.screenToContentsTransform().inverse().transformPoint(0, 0);
            dragData.defaultDropAction = dropActionType.embed;
            dragData.canEmbed = true;
            DragManager.StartDocumentDrag([dragDocView.ContentDiv!], dragData, origin[0], origin[1], { hideSource: false });
            return true;
        }
        return false;
    };

    _ref = React.createRef<HTMLDivElement>();
    @observable _tooltipOpen: boolean = false;
    @computed get templateMenu() {
        return (
            <div ref={this._ref}>
                <TemplateMenu
                    docViews={this._props
                        .views()
                        .filter(v => v)
                        .map(v => v as DocumentView)}
                />
            </div>
        );
    }
    @computed
    get templateButton() {
        return !this.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);
                    })}>
                    <Popup icon={<FaEdit />} popup={this.templateMenu} popupContainsPt={returnTrue} />
                </div>
            </Tooltip>
        );
    }

    openContextMenu = (e: PointerEvent) => {
        let child = DocumentView.Selected()[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 = () => {
        this._captureEndLinkLayout = !this._captureEndLinkLayout;
    };
    @observable _captureEndLinkContent = false;
    @action
    captureEndLinkContent = () => {
        this._captureEndLinkContent = !this._captureEndLinkContent;
    };

    @action
    captureEndLinkState = () => {
        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;

        return (
            <div className="documentButtonBar">
                <div className="documentButtonBar-button">
                    <DocumentLinksButton View={this.view0} AlwaysOn InMenu ShowCount />
                </div>
                {this._showLinkPopup ? (
                    <div style={{ position: 'absolute', zIndex: 1000 }}>
                        <LinkPopup key="popup" linkCreated={emptyFunction} 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}
                <div className="documentButtonBar-button">{this.templateButton}</div>
                {!DocumentView.Selected().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>
                <div className="documentButtonBar-button">{this.calendarButton}</div>
                <div className="documentButtonBar-button">{this.aiEditorButton}</div>
                <div className="documentButtonBar-button">{this.keywordButton}</div>
                {!Doc.UserDoc().documentLinksButton_fullMenu ? null : <div className="documentButtonBar-button">{this.shareButton}</div>}
                <div className="documentButtonBar-button">{this.menuButton}</div>
            </div>
        );
    }
}
