import { action, computed, makeObservable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc, DocListCast, Opt, StrListCast } from '../../../fields/Doc';
import { Highlight } from '../../../fields/DocSymbols';
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';

interface IRegionAnnotationProps {
    x: number;
    y: number;
    width: number;
    height: number;
    opacity: () => number;
    background: () => string;
    outline: () => string | undefined;
}

const RegionAnnotation = function (props: IRegionAnnotationProps) {
    return (
        <div
            className="htmlAnnotation"
            style={{
                left: NumCast(props.x),
                top: NumCast(props.y),
                width: NumCast(props.width),
                height: NumCast(props.height),
                opacity: props.opacity(),
                outline: props.outline(),
                backgroundColor: props.background(),
            }}
        />
    );
};

interface IAnnotationProps extends FieldViewProps {
    annoDoc: Doc;
    containerDataDoc: Doc;
    fieldKey: string;
    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.annoDoc).find(link => {
            const a1 = LinkManager.getOppositeAnchor(link, this._props.annoDoc);
            return a1 && Doc.GetBrushStatus(DocCast(a1.annotationOn, a1));
        });
        return found;
    }

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

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

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

    isTargetToggler = () => BoolCast(this._props.annoDoc.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.deleteAnnotation;
        AnchorMenu.Instance.Pinned = false;
        AnchorMenu.Instance.PinToPres = this.pinToPres;
        AnchorMenu.Instance.MakeTargetToggle = this.makeTargetToggle;
        AnchorMenu.Instance.IsTargetToggler = this.isTargetToggler;
        AnchorMenu.Instance.ShowTargetTrail = () => this.showTargetTrail(this._props.annoDoc);
        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._props.annoDoc, false);
        }
    };
    brushed = () => this._props.annoDoc && Doc.GetBrushHighlightStatus(this._props.annoDoc);
    opacity = () => (this.brushed() === Doc.DocBrushStatus.highlighted ? 0.5 : 1);
    outline = () => (this.linkHighlighted ? 'solid 1px lightBlue' : undefined);
    background = () => (this._props.annoDoc[Highlight] ? 'orange' : StrCast(this._props.annoDoc.backgroundColor));
    render() {
        return (
            <div style={{ display: this._props.annoDoc.textCopied && !Doc.GetBrushHighlightStatus(this._props.annoDoc) ? 'none' : undefined }}>
                {StrListCast(this._props.annoDoc.text_inlineAnnotations)
                    .map(a => a.split?.(':'))
                    .filter(fields => fields)
                    .map(([x, y, width, height]) => (
                        <div
                            key={'' + x + y + width + height}
                            style={{ pointerEvents: this._props.pointerEvents?.() as any }}
                            onPointerDown={this.onPointerDown}
                            onContextMenu={this.onContextMenu}
                            onPointerEnter={() => {
                                Doc.BrushDoc(this._props.annoDoc);
                            }}
                            onPointerLeave={() => {
                                Doc.UnBrushDoc(this._props.annoDoc);
                            }}>
                            <RegionAnnotation //
                                x={Number(x)}
                                y={Number(y)}
                                width={Number(width)}
                                height={Number(height)}
                                outline={this.outline}
                                background={this.background}
                                opacity={this.opacity}
                            />
                        </div>
                    ))}
            </div>
        );
    }
}
