import { action, computed, makeObservable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { NumCast, StrCast } from '../../../fields/Types';
import { TraceMobx } from '../../../fields/util';
import { DocUtils } from '../../documents/DocUtils';
import { DocumentType } from '../../documents/DocumentTypes';
import { Docs } from '../../documents/Documents';
import { undoBatch } from '../../util/UndoManager';
import { ViewBoxBaseComponent } from '../DocComponent';
import { StyleProp } from '../StyleProp';
import { DocumentView } from './DocumentView';
import './EquationBox.scss';
import { FieldView, FieldViewProps } from './FieldView';
import EquationEditor from './formattedText/EquationEditor';
import { FormattedTextBox } from './formattedText/FormattedTextBox';

@observer
export class EquationBox extends ViewBoxBaseComponent<FieldViewProps>() {
    public static LayoutString(fieldKey: string) {
        return FieldView.LayoutString(EquationBox, fieldKey);
    }
    _ref: React.RefObject<EquationEditor> = React.createRef();

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

    componentDidMount() {
        this._props.setContentViewBox?.(this);
        if (DocumentView.SelectOnLoad === this.Document && (!DocumentView.LightboxDoc() || DocumentView.LightboxContains(this.DocumentView?.()))) {
            this._props.select(false);

            this._ref.current?.mathField.focus();
            this.dataDoc.text === 'x' && this._ref.current?.mathField.select();
            DocumentView.SetSelectOnLoad(undefined);
        }
        reaction(
            () => this._props.isSelected(),
            selected => {
                if (this._ref.current) {
                    if (selected) (this._ref.current.element.current?.children[0] as HTMLElement).addEventListener('keydown', this.keyPressed, true);
                    else (this._ref.current.element.current?.children[0] as HTMLElement).removeEventListener('keydown', this.keyPressed);
                }
            },
            { fireImmediately: true }
        );
    }
    @computed get fontSize()       { return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontSize) as string; } // prettier-ignore
    @computed get fontColor()      { return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontColor) as string; } // prettier-ignore

    @action
    keyPressed = (e: KeyboardEvent) => {
        if (e.key === 'Enter') {
            const nextEq = Docs.Create.EquationDocument(e.shiftKey ? StrCast(this.dataDoc.text) : '', {
                title: '# math',
                _width: NumCast(this.layoutDoc._width),
                _height: NumCast(this.layoutDoc._height),
                nativeHeight: NumCast(this.dataDoc.nativeHeight),
                nativeWidth: NumCast(this.dataDoc.nativeWidth),
                x: NumCast(this.layoutDoc.x),
                y: NumCast(this.layoutDoc.y) + NumCast(this.Document._height) + 10,
                backgroundColor: StrCast(this.Document.backgroundColor),
                color: StrCast(this.Document.color),
                fontSize: this.fontSize,
            });
            DocumentView.SetSelectOnLoad(nextEq);
            this._props.addDocument?.(nextEq);
            e.stopPropagation();
        }
        if (e.key === 'Tab') {
            const graph = Docs.Create.FunctionPlotDocument([this.Document], {
                x: NumCast(this.layoutDoc.x) + NumCast(this.layoutDoc._width),
                y: NumCast(this.layoutDoc.y),
                _width: 400,
                _height: 300,
                backgroundColor: 'white',
            });
            const link = DocUtils.MakeLink(this.Document, graph, { layout_isSvg: true, link_relationship: 'function', link_description: 'input' });
            this._props.addDocument?.(graph);
            link && this._props.addDocument?.(link);
            e.stopPropagation();
        }
        if (e.key === 'Backspace' && !this.dataDoc.text) this._props.removeDocument?.(this.Document);
    };
    @undoBatch
    onChange = (str: string) => {
        this.dataDoc.text = str;
    };

    updateSize = (mathSpan: HTMLSpanElement) => {
        const style = getComputedStyle(mathSpan);
        const styleWidth = Number(style.width.replace('px', '') || 0);
        const styleHeight = Number(style.height.replace('px', '') || 0);
        const mathWidth = Math.max(35, NumCast(this.layoutDoc.xMargin) * 2 + styleWidth);
        const mathHeight = Math.max(20, NumCast(this.layoutDoc.yMargin) * 2 + styleHeight);
        const nScale = !this.dataDoc.nativeWidth ? 1
            : (prevNwidth => {  // if equation has been scaled then editing the expression must also edit the native dimensions to keep the aspect ratio
                    [this.dataDoc.nativeWidth, this.dataDoc.nativeHeight] = [mathWidth, mathHeight];
                    return  NumCast(this.layoutDoc._width) / prevNwidth;
                })(NumCast(this.dataDoc.nativeWidth)); // prettier-ignore

        this.layoutDoc._width = mathWidth * nScale;
        this.layoutDoc._height = mathHeight * nScale;
    };
    render() {
        TraceMobx();
        const scale = this._props.NativeDimScaling?.() || 1;
        return (
            <div
                ref={r => r && this._ref.current?.element.current && this.updateSize(this._ref.current?.element.current)}
                className="equationBox-cont"
                onKeyDown={e => e.stopPropagation()}
                onPointerDown={e => !e.ctrlKey && e.stopPropagation()}
                onBlur={() => {
                    FormattedTextBox.LiveTextUndo?.end();
                }}
                style={{
                    transform: `scale(${scale})`,
                    minWidth: `${100 / scale}%`,
                    height: `${100 / scale}%`,
                    pointerEvents: !this._props.isContentActive() ? 'none' : undefined,
                    fontSize: this.fontSize,
                    color: this.fontColor,
                    paddingLeft: NumCast(this.layoutDoc.xMargin),
                    paddingRight: NumCast(this.layoutDoc.xMargin),
                    paddingTop: NumCast(this.layoutDoc.yMargin),
                    paddingBottom: NumCast(this.layoutDoc.yMargin),
                }}>
                <EquationEditor ref={this._ref} value={StrCast(this.dataDoc.text, '')} spaceBehavesLikeTab onChange={this.onChange} autoCommands="pi theta sqrt sum prod alpha beta gamma rho" autoOperatorNames="sin cos tan" />
            </div>
        );
    }
}

Docs.Prototypes.TemplateMap.set(DocumentType.EQUATION, {
    layout: { view: EquationBox, dataField: 'text' },
    options: {
        acl: '',
        _xMargin: 10,
        _yMargin: 10,
        fontSize: '14px',
        _nativeWidth: 40,
        _nativeHeight: 40,
        _layout_reflowHorizontal: false,
        _layout_reflowVertical: false,
        _layout_nativeDimEditable: false,
        layout_hideDecorationTitle: true,
        systemIcon: 'BsCalculatorFill',
    }, // systemIcon: 'BsSuperscript' + BsSubscript
});
