import { action, makeObservable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { DivHeight, DivWidth } from '../../../ClientUtils';
import { Doc } from '../../../fields/Doc';
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 { DocumentView } from './DocumentView';
import './EquationBox.scss';
import { FieldView, FieldViewProps } from './FieldView';
import EquationEditor from './formattedText/EquationEditor';

@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 (Doc.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();
            Doc.SetSelectOnLoad(undefined);
        }
        reaction(
            () => StrCast(this.dataDoc.text),
            text => {
                if (text && text !== this._ref.current!.mathField.latex()) {
                    this._ref.current!.mathField.latex(text);
                }
            }
            // { fireImmediately: true }
        );
        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 }
        );
    }

    @action
    keyPressed = (e: KeyboardEvent) => {
        const _height = DivHeight(this._ref.current!.element?.current);
        const _width = DivWidth(this._ref.current!.element?.current);
        if (e.key === 'Enter') {
            const nextEq = Docs.Create.EquationDocument(e.shiftKey ? StrCast(this.dataDoc.text) : 'x', {
                title: '# math',
                _width,
                _height: 25,
                x: NumCast(this.layoutDoc.x),
                y: NumCast(this.layoutDoc.y) + _height + 10,
            });
            Doc.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 = () => {
        const style = this._ref.current?.element.current && getComputedStyle(this._ref.current.element.current);
        if (style?.width.endsWith('px') && style?.height.endsWith('px')) {
            if (this.layoutDoc._nativeWidth) {
                // if equation has been scaled then editing the expression must also edit the native dimensions to keep the aspect ratio
                const prevNwidth = NumCast(this.layoutDoc._nativeWidth);
                const newNwidth = (this.layoutDoc._nativeWidth = Math.max(35, Number(style.width.replace('px', ''))));
                const newNheight = (this.layoutDoc._nativeHeight = Math.max(25, Number(style.height.replace('px', ''))));
                this.layoutDoc._width = (NumCast(this.layoutDoc._width) * NumCast(this.layoutDoc._nativeWidth)) / prevNwidth;
                this.layoutDoc._height = (NumCast(this.layoutDoc._width) * newNheight) / newNwidth;
            } else {
                this.layoutDoc._width = Math.max(35, Number(style.width.replace('px', '')));
                this.layoutDoc._height = Math.max(25, Number(style.height.replace('px', '')));
            }
        }
    };
    render() {
        TraceMobx();
        const scale = (this._props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._freeform_scale, 1);
        return (
            <div
                ref={() => this.updateSize()}
                className="equationBox-cont"
                onPointerDown={e => !e.ctrlKey && e.stopPropagation()}
                style={{
                    transform: `scale(${scale})`,
                    height: `${100 / scale}%`,
                    pointerEvents: !this._props.isSelected() ? 'none' : undefined,
                    fontSize: StrCast(this.Document._text_fontSize),
                }}
                onKeyDown={e => e.stopPropagation()}>
                <EquationEditor ref={this._ref} value={StrCast(this.dataDoc.text, 'x')} 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: '', fontSize: '14px', _layout_reflowHorizontal: true, _layout_reflowVertical: true, _layout_nativeDimEditable: true, layout_hideDecorationTitle: true, systemIcon: 'BsCalculatorFill' }, // systemIcon: 'BsSuperscript' + BsSubscript
});
