/* eslint-disable react/jsx-props-no-spreading */
import { action, computed, makeObservable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc, DocListCast, Opt } from '../../../fields/Doc';
import { Id } from '../../../fields/FieldSymbols';
import { List } from '../../../fields/List';
import { BoolCast, DocCast, NumCast, StrCast } from '../../../fields/Types';
import { LinkFollower } from '../../util/LinkFollower';
import { LinkManager } from '../../util/LinkManager';
import { undoable } from '../../util/UndoManager';
import { ObservableReactComponent } from '../ObservableReactComponent';
import { OpenWhere } from '../nodes/DocumentView';
import { FieldViewProps } from '../nodes/FieldView';
import { AnchorMenu } from './AnchorMenu';
import './Annotation.scss';
import { Highlight } from '../../../fields/DocSymbols';

interface IAnnotationProps extends FieldViewProps {
    anno: Doc;
    dataDoc: Doc;
    fieldKey: string;
    showInfo?: (anno: Opt<Doc>) => void;
    pointerEvents?: () => Opt<string>;
}
@observer
export class Annotation extends ObservableReactComponent<IAnnotationProps> {
    constructor(props: any) {
        super(props);
        makeObservable(this);
    }

    @computed get linkHighlighted() {
        const found = LinkManager.Instance.getAllDirectLinks(this._props.anno).find(link => {
            const a1 = LinkManager.getOppositeAnchor(link, this._props.anno);
            return a1 && Doc.GetBrushStatus(DocCast(a1.annotationOn, a1));
        });
        return found;
    }
    linkHighlightedFunc = () => this.linkHighlighted;
    highlightedFunc = () => this._props.anno[Highlight];

    deleteAnnotation = undoable(() => {
        const docAnnotations = DocListCast(this._props.dataDoc[this._props.fieldKey]);
        this._props.dataDoc[this._props.fieldKey] = new List<Doc>(docAnnotations.filter(a => a !== this._props.anno));
        AnchorMenu.Instance.fadeOut(true);
        this._props.select(false);
    }, 'delete annotation');

    pinToPres = undoable(() => this._props.pinToPres(this._props.anno, {}), 'pin to pres');

    render() {
        return (
            <div style={{ display: this._props.anno.textCopied && !Doc.GetBrushHighlightStatus(this._props.anno) ? 'none' : undefined }}>
                {DocListCast(this._props.anno.text_inlineAnnotations).map(a => (
                    // eslint-disable-next-line no-use-before-define
                    <RegionAnnotation
                        pointerEvents={this._props.pointerEvents}
                        {...this._props}
                        highlighted={this.highlightedFunc}
                        linkHighlighted={this.linkHighlightedFunc}
                        pinToPres={this.pinToPres}
                        deleteAnnotation={this.deleteAnnotation}
                        document={a}
                        key={a[Id]}
                    />
                ))}
            </div>
        );
    }
}

interface IRegionAnnotationProps extends IAnnotationProps {
    document: Doc;
    linkHighlighted: () => Doc | undefined;
    highlighted: () => any;
    deleteAnnotation: () => void;
    pinToPres: (...args: any[]) => void;
    pointerEvents?: () => Opt<string>;
}
@observer
class RegionAnnotation extends ObservableReactComponent<IRegionAnnotationProps> {
    private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();

    @computed get regionDoc() {
        return DocCast(this._props.document.embedContainer, this._props.document);
    }

    makeTargetToggle = undoable(() => { this.regionDoc.followLinkToggle = !this.regionDoc.followLinkToggle }, "set link toggle"); // prettier-ignore

    isTargetToggler = () => BoolCast(this.regionDoc.followLinkToggle);

    showTargetTrail = undoable((anchor: Doc) => {
        const trail = DocCast(anchor.presentationTrail);
        if (trail) {
            Doc.ActivePresentation = trail;
            this._props.addDocTab(trail, OpenWhere.replaceRight);
        }
    }, 'show target trail');

    @action
    onContextMenu = (e: React.MouseEvent) => {
        AnchorMenu.Instance.Status = 'annotation';
        AnchorMenu.Instance.Delete = this._props.deleteAnnotation;
        AnchorMenu.Instance.Pinned = false;
        AnchorMenu.Instance.PinToPres = this._props.pinToPres;
        AnchorMenu.Instance.MakeTargetToggle = this.makeTargetToggle;
        AnchorMenu.Instance.IsTargetToggler = this.isTargetToggler;
        AnchorMenu.Instance.ShowTargetTrail = () => this.showTargetTrail(this.regionDoc);
        AnchorMenu.Instance.jumpTo(e.clientX, e.clientY, true);
        e.stopPropagation();
        e.preventDefault();
    };
    @action
    onPointerDown = (e: React.PointerEvent) => {
        if (e.button === 2 || e.ctrlKey) {
            e.stopPropagation();
            e.preventDefault();
        } else if (e.button === 0) {
            e.stopPropagation();
            LinkFollower.FollowLink(undefined, this.regionDoc, false);
        }
    };

    render() {
        const brushed = this.regionDoc && Doc.GetBrushHighlightStatus(this.regionDoc);
        return (
            <div
                className="htmlAnnotation"
                ref={this._mainCont}
                onPointerEnter={action(() => {
                    Doc.BrushDoc(this._props.anno);
                    this._props.showInfo?.(this._props.anno);
                })}
                onPointerLeave={action(() => {
                    Doc.UnBrushDoc(this._props.anno);
                    this._props.showInfo?.(undefined);
                })}
                onPointerDown={this.onPointerDown}
                onContextMenu={this.onContextMenu}
                style={{
                    left: NumCast(this._props.document.x),
                    top: NumCast(this._props.document.y),
                    width: NumCast(this._props.document._width),
                    height: NumCast(this._props.document._height),
                    opacity: brushed === Doc.DocBrushStatus.highlighted ? 0.5 : undefined,
                    pointerEvents: this._props.pointerEvents?.() as any,
                    outline: this._props.linkHighlighted() ? 'solid 1px lightBlue' : undefined,
                    backgroundColor: this._props.highlighted() ? 'orange' : StrCast(this._props.document.backgroundColor),
                }}
            />
        );
    }
}
