import { Property } from 'csstype';
import { action, computed, makeObservable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import * as textfit from 'textfit';
import { Field, FieldType } from '../../../fields/Doc';
import { BoolCast, NumCast, StrCast } from '../../../fields/Types';
import { TraceMobx } from '../../../fields/util';
import { DocumentType } from '../../documents/DocumentTypes';
import { Docs } from '../../documents/Documents';
import { DragManager } from '../../util/DragManager';
import { ViewBoxBaseComponent } from '../DocComponent';
import { PinDocView, PinProps } from '../PinFuncs';
import { StyleProp } from '../StyleProp';
import { FieldView, FieldViewProps } from './FieldView';
import './LabelBox.scss';

@observer
export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
    public static LayoutString(fieldKey: string) {
        return FieldView.LayoutString(LabelBox, fieldKey);
    }
    private dropDisposer?: DragManager.DragDropDisposer;
    private _timeout: NodeJS.Timeout | undefined;
    _divRef: HTMLDivElement | null = null;

    constructor(props: FieldViewProps) {
        super(props);
        makeObservable(this);
    }

    protected createDropTarget = (ele: HTMLDivElement) => {
        this.dropDisposer?.();
        if (ele) {
            this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.Document);
        }
    };

    @computed get Title() {
        return Field.toString(this.dataDoc[this.fieldKey] as FieldType) || StrCast(this.Document.title);
    }

    @computed get backgroundColor() {
        return this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor) as string;
    }

    componentDidMount() {
        this._props.setContentViewBox?.(this);
    }
    componentWillUnMount() {
        this._timeout && clearTimeout(this._timeout);
    }

    specificContextMenu = (): void => {};

    drop = (/* e: Event, de: DragManager.DropEvent */) => {
        return false;
    };

    getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
        if (!pinProps) return this.Document;
        const anchor = Docs.Create.ConfigDocument({ title: StrCast(this.Document.title), annotationOn: this.Document });

        if (anchor) {
            if (!addAsAnnotation) anchor.backgroundColor = 'transparent';
            //  addAsAnnotation && this.addDocument(anchor);
            PinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}) } }, this.Document);
            return anchor;
        }
        return anchor;
    };

    fitTextToBox = (
        r: HTMLElement | null | undefined
    ): {
        minFontSize: number;
        maxFontSize: number;
        multiLine: boolean;
        alignHoriz: boolean;
        alignVert: boolean;
        detectMultiLine: boolean;
    } => {
        this._timeout && clearTimeout(this._timeout);
        const textfitParams = {
            minFontSize: NumCast(this.layoutDoc._label_minFontSize, 1),
            maxFontSize: NumCast(this.layoutDoc._label_maxFontSize, 100),
            multiLine: BoolCast(this.layoutDoc._singleLine, true) ? false : true,
            alignHoriz: true,
            alignVert: true,
            detectMultiLine: true,
        };
        if (r) {
            if (!r.offsetHeight || !r.offsetWidth) {
                console.log("CAN'T FIT TO EMPTY BOX");
                this._timeout && clearTimeout(this._timeout);
                this._timeout = setTimeout(() => this.fitTextToBox(r));
                return textfitParams;
            }
            textfit(r, textfitParams);
        }
        return textfitParams;
    };
    render() {
        TraceMobx();
        const boxParams = this.fitTextToBox(undefined); // this causes mobx to trigger re-render when data changes
        const label = this.Title.startsWith('#') ? null : this.Title;
        return (
            <div key={label?.length} className="labelBox-outerDiv" ref={this.createDropTarget} onContextMenu={this.specificContextMenu} style={{ boxShadow: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BoxShadow) as string }}>
                <div
                    className="labelBox-mainButton"
                    style={{
                        backgroundColor: this.backgroundColor,
                        // fontSize: StrCast(this.layoutDoc._text_fontSize),
                        color: StrCast(this.layoutDoc._color),
                        fontFamily: StrCast(this.layoutDoc._text_fontFamily) || 'inherit',
                        letterSpacing: StrCast(this.layoutDoc.letterSpacing),
                        textTransform: StrCast(this.layoutDoc.textTransform) as Property.TextTransform,
                        paddingLeft: NumCast(this.layoutDoc._xPadding),
                        paddingRight: NumCast(this.layoutDoc._xPadding),
                        paddingTop: NumCast(this.layoutDoc._yPadding),
                        paddingBottom: NumCast(this.layoutDoc._yPadding),
                        width: this._props.PanelWidth(),
                        height: this._props.PanelHeight(),
                        whiteSpace: 'multiLine' in boxParams && boxParams.multiLine ? 'pre-wrap' : 'pre',
                    }}>
                    <div
                        style={{
                            width: this._props.PanelWidth() - 2 * NumCast(this.layoutDoc._xPadding),
                            height: this._props.PanelHeight() - 2 * NumCast(this.layoutDoc._yPadding),
                            outline: 'unset !important',
                        }}
                        onKeyDown={action(e => {
                            e.stopPropagation();
                        })}
                        onKeyUp={action(e => {
                            e.stopPropagation();
                            if (e.key === 'Enter') {
                                this.dataDoc[this.fieldKey] = this._divRef?.innerText ?? '';
                                setTimeout(() => this._props.select(false));
                            }
                        })}
                        onBlur={() => {
                            this.dataDoc[this.fieldKey] = this._divRef?.innerText ?? '';
                        }}
                        contentEditable={this._props.onClickScript?.() ? false : true}
                        ref={r => {
                            this._divRef = r;
                            this.fitTextToBox(r);
                            if (this._props.isSelected() && this._divRef) {
                                const range = document.createRange();
                                range.setStart(this._divRef, this._divRef.childNodes.length);
                                range.setEnd(this._divRef, this._divRef.childNodes.length);
                                const sel = window.getSelection();
                                sel?.removeAllRanges();
                                sel?.addRange(range);
                            }
                        }}>
                        {label}
                    </div>
                </div>
            </div>
        );
    }
}

Docs.Prototypes.TemplateMap.set(DocumentType.LABEL, {
    layout: { view: LabelBox, dataField: 'title' },
    options: { acl: '', _singleLine: true, _layout_nativeDimEditable: true, _layout_reflowHorizontal: true, _layout_reflowVertical: true },
});
Docs.Prototypes.TemplateMap.set(DocumentType.BUTTON, {
    layout: { view: LabelBox, dataField: 'title' },
    options: { acl: '', _layout_nativeDimEditable: true, _layout_reflowHorizontal: true, _layout_reflowVertical: true },
});
