import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@mui/material';
import { action, computed, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../Utils';
import { Doc } from '../../../fields/Doc';
import { Cast, DocCast, StrCast } from '../../../fields/Types';
import { WebField } from '../../../fields/URLField';
import { DocumentType } from '../../documents/DocumentTypes';
import { DocumentManager } from '../../util/DocumentManager';
import { DragManager } from '../../util/DragManager';
import { LinkFollower } from '../../util/LinkFollower';
import { LinkManager } from '../../util/LinkManager';
import { SelectionManager } from '../../util/SelectionManager';
import { SettingsManager } from '../../util/SettingsManager';
import { undoBatch } from '../../util/UndoManager';
import { ObservableReactComponent } from '../ObservableReactComponent';
import { DocumentView, DocumentViewInternal, OpenWhere } from '../nodes/DocumentView';
import { LinkInfo } from '../nodes/LinkDocPreview';
import './LinkMenuItem.scss';

interface LinkMenuItemProps {
    groupType: string;
    linkDoc: Doc;
    docView: DocumentView;
    sourceDoc: Doc;
    destinationDoc: Doc;
    clearLinkEditor?: () => void;
    menuRef: React.Ref<HTMLDivElement>;
    itemHandler?: (doc: Doc) => void;
}

// drag links and drop link targets (embedding them if needed)
export async function StartLinkTargetsDrag(dragEle: HTMLElement, docView: DocumentView, downX: number, downY: number, sourceDoc: Doc, specificLinks?: Doc[]) {
    const draggedDocs = (specificLinks ? specificLinks : LinkManager.Links(sourceDoc)).map(link => LinkManager.getOppositeAnchor(link, sourceDoc)).filter(l => l) as Doc[];

    if (draggedDocs.length) {
        const moddrag: Doc[] = [];
        for (const draggedDoc of draggedDocs) {
            const doc = await Cast(draggedDoc.annotationOn, Doc);
            if (doc) moddrag.push(doc);
        }

        const dragData = new DragManager.DocumentDragData(moddrag.length ? moddrag : draggedDocs);
        dragData.canEmbed = true;
        dragData.dropAction = 'embed';

        DragManager.StartDocumentDrag([dragEle], dragData, downX, downY, undefined);
    }
}

@observer
export class LinkMenuItem extends ObservableReactComponent<LinkMenuItemProps> {
    private _drag = React.createRef<HTMLDivElement>();
    _editRef = React.createRef<HTMLDivElement>();
    constructor(props: any) {
        super(props);
        makeObservable(this);
    }

    @observable private _showMore: boolean = false;
    @action toggleShowMore(e: React.PointerEvent) {
        e.stopPropagation();
        this._showMore = !this._showMore;
    }

    @computed get sourceAnchor() {
        const ldoc = this._props.linkDoc;
        if (this._props.sourceDoc !== ldoc.link_anchor_1 && this._props.sourceDoc !== ldoc.link_anchor_2) {
            if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.link_anchor_1).annotationOn), this._props.sourceDoc)) return DocCast(ldoc.link_anchor_1);
            if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.link_anchor_2).annotationOn), this._props.sourceDoc)) return DocCast(ldoc.link_anchor_2);
        }
        return this._props.sourceDoc;
    }

    onIconDown = (e: React.PointerEvent) => {
        setupMoveUpEvents(this, e, returnFalse, returnFalse, () => {
            const ancestor = DocumentManager.LinkCommonAncestor(this._props.linkDoc);
            if (!ancestor?.ComponentView?.removeDocument?.(this._props.linkDoc)) {
                ancestor?.ComponentView?.addDocument?.(this._props.linkDoc);
            }
        });
    };

    onEdit = (e: React.PointerEvent) => {
        setupMoveUpEvents(
            this,
            e,
            e => {
                const dragData = new DragManager.DocumentDragData([this._props.linkDoc], 'embed');
                dragData.dropPropertiesToRemove = ['hidden'];
                DragManager.StartDocumentDrag([this._editRef.current!], dragData, e.x, e.y);
                return true;
            },
            emptyFunction,
            action(() => {
                const trail = DocCast(this._props.docView.Document.presentationTrail);
                if (trail) {
                    Doc.ActivePresentation = trail;
                    DocumentViewInternal.addDocTabFunc(trail, OpenWhere.replaceRight);
                } else {
                    SelectionManager.SelectView(this._props.docView, false);
                    LinkManager.Instance.currentLink = this._props.linkDoc === LinkManager.Instance.currentLink ? undefined : this._props.linkDoc;
                    LinkManager.Instance.currentLinkAnchor = LinkManager.Instance.currentLink ? this.sourceAnchor : undefined;

                    if ((SettingsManager.Instance.propertiesWidth ?? 0) < 100) {
                        setTimeout(action(() => (SettingsManager.Instance.propertiesWidth = 250)));
                    }
                }
            })
        );
    };

    onLinkButtonDown = (e: React.PointerEvent): void => {
        setupMoveUpEvents(
            this,
            e,
            e => {
                const eleClone: any = this._drag.current!.cloneNode(true);
                eleClone.style.transform = `translate(${e.x}px, ${e.y}px)`;
                StartLinkTargetsDrag(eleClone, this._props.docView, e.x, e.y, this._props.sourceDoc, [this._props.linkDoc]);
                this._props.clearLinkEditor?.();
                return true;
            },
            emptyFunction,
            () => {
                this._props.clearLinkEditor?.();
                if (this._props.itemHandler) {
                    this._props.itemHandler?.(this._props.linkDoc);
                } else {
                    const focusDoc =
                        Cast(this._props.linkDoc.link_anchor_1, Doc, null)?.annotationOn === this._props.sourceDoc
                            ? Cast(this._props.linkDoc.link_anchor_1, Doc, null)
                            : Cast(this._props.linkDoc.link_anchor_2, Doc, null)?.annotationOn === this._props.sourceDoc
                              ? Cast(this._props.linkDoc.link_anchor_12, Doc, null)
                              : undefined;

                    if (focusDoc) this._props.docView._props.focus(focusDoc, { instant: true });
                    LinkFollower.FollowLink(this._props.linkDoc, this._props.sourceDoc, false);
                }
            }
        );
    };

    deleteLink = (e: React.PointerEvent): void => setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => LinkManager.Instance.deleteLink(this._props.linkDoc))));
    @observable _hover = false;
    docView = () => this._props.docView;
    render() {
        const destinationIcon = Doc.toIcon(this._props.destinationDoc) as any as IconProp;

        const title = StrCast(this._props.destinationDoc.title).length > 18 ? StrCast(this._props.destinationDoc.title).substr(0, 14) + '...' : this._props.destinationDoc.title;

        const source =
            this._props.sourceDoc.type === DocumentType.RTF
                ? this._props.linkDoc.storedText
                    ? StrCast(this._props.linkDoc.storedText).length > 17
                        ? StrCast(this._props.linkDoc.storedText).substr(0, 18)
                        : this._props.linkDoc.storedText
                    : undefined
                : undefined;

        return (
            <div
                className="linkMenu-item"
                onPointerEnter={action(e => (this._hover = true))}
                onPointerLeave={action(e => (this._hover = false))}
                style={{
                    fontSize: this._hover ? 'larger' : undefined,
                    fontWeight: this._hover ? 'bold' : undefined,
                    background: LinkManager.Instance.currentLink === this._props.linkDoc ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor,
                }}>
                <div className="linkMenu-item-content expand-two">
                    <div
                        ref={this._drag}
                        className="linkMenu-name" //title="drag to view target. click to customize."
                        onPointerDown={this.onLinkButtonDown}>
                        <div className="linkMenu-item-buttons">
                            <Tooltip title={<div className="dash-tooltip">Edit Link</div>}>
                                <div className="button" ref={this._editRef} onPointerDown={this.onEdit} onClick={e => e.stopPropagation()}>
                                    <FontAwesomeIcon className="fa-icon" icon="edit" size="sm" />
                                </div>
                            </Tooltip>
                        </div>
                        <div
                            className="linkMenu-text"
                            onPointerLeave={LinkInfo.Clear}
                            onPointerEnter={e =>
                                this._props.linkDoc &&
                                this._props.clearLinkEditor &&
                                LinkInfo.SetLinkInfo({
                                    DocumentView: this.docView,
                                    styleProvider: this._props.docView._props.styleProvider,
                                    linkSrc: this._props.sourceDoc,
                                    linkDoc: this._props.linkDoc,
                                    showHeader: false,
                                    location: [(this._drag.current?.getBoundingClientRect().left ?? 100) + 40, (this._drag.current?.getBoundingClientRect().top ?? e.clientY) + 25],
                                    noPreview: false,
                                })
                            }>
                            {source ? (
                                <p className="linkMenu-source-title">
                                    {' '}
                                    <b>Source: {StrCast(source)}</b>
                                </p>
                            ) : null}
                            <div className="linkMenu-title-wrapper">
                                <Tooltip title={<div className="dash-tooltip">Show/Hide Link</div>}>
                                    <div title="click to show link" className="destination-icon-wrapper" onPointerDown={this.onIconDown}>
                                        <FontAwesomeIcon className="destination-icon" icon={destinationIcon} size="sm" />
                                    </div>
                                </Tooltip>
                                <Tooltip title={<div className="dash-tooltip">Follow Link</div>}>
                                    <p className="linkMenu-destination-title">
                                        {this._props.linkDoc.linksToAnnotation && Cast(this._props.destinationDoc.data, WebField)?.url.href === this._props.linkDoc.annotationUri ? 'Annotation in' : ''} {StrCast(title)}
                                    </p>
                                </Tooltip>
                            </div>
                            {!this._props.linkDoc.link_description ? null : <p className="linkMenu-description">{StrCast(this._props.linkDoc.link_description).split('\n')[0].substring(0, 50)}</p>}
                        </div>

                        <div className="linkMenu-item-buttons">
                            <Tooltip title={<div className="dash-tooltip">Delete Link</div>}>
                                <div className="linkMenu-deleteButton" onPointerDown={this.deleteLink} onClick={e => e.stopPropagation()}>
                                    <FontAwesomeIcon className="fa-icon" icon="trash" size="sm" />
                                </div>
                            </Tooltip>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}
