import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import './RadialMenu.scss';
import { RadialMenuItem, RadialMenuProps } from './RadialMenuItem';

@observer
export class RadialMenu extends React.Component {
    // eslint-disable-next-line no-use-before-define
    static Instance: RadialMenu;
    static readonly buffer = 20;

    @observable private _mouseX: number = -1;
    @observable private _mouseY: number = -1;
    @observable private _shouldDisplay: boolean = false;
    @observable private _mouseDown: boolean = false;
    @observable private _closest: number = -1;
    @observable private _pageX: number = 0;
    @observable private _pageY: number = 0;
    @observable _display: boolean = false;
    @observable private _yRelativeToTop: boolean = true;
    @observable private _items: Array<RadialMenuProps> = [];
    private _reactionDisposer?: IReactionDisposer;

    constructor(props: any) {
        super(props);
        makeObservable(this);
        RadialMenu.Instance = this;
    }

    componentDidMount() {
        document.addEventListener('pointerdown', this.onPointerDown);
        document.addEventListener('pointerup', this.onPointerUp);
        this.previewcircle();
        this._reactionDisposer = reaction(
            () => this._shouldDisplay,
            () =>
                this._shouldDisplay &&
                !this._mouseDown &&
                runInAction(() => {
                    this._display = true;
                })
        );
    }

    componentDidUpdate() {
        this.previewcircle();
    }
    componentWillUnmount() {
        document.removeEventListener('pointerdown', this.onPointerDown);

        document.removeEventListener('pointerup', this.onPointerUp);
        this._reactionDisposer && this._reactionDisposer();
    }

    @computed get menuItems() {
        // eslint-disable-next-line react/jsx-props-no-spreading
        return this._items.map((item, index) => <RadialMenuItem {...item} key={item.description} closeMenu={this.closeMenu} max={this._items.length} min={index} selected={this._closest} />);
    }

    catchTouch = (te: React.TouchEvent) => {
        te.stopPropagation();
        te.preventDefault();
    };

    @action
    onPointerDown = (e: PointerEvent) => {
        this._mouseDown = true;
        this._mouseX = e.clientX;
        this._mouseY = e.clientY;
        document.addEventListener('pointermove', this.onPointerMove);
    };

    @action
    onPointerMove = (e: PointerEvent) => {
        const curX = e.clientX;
        const curY = e.clientY;
        const deltX = this._mouseX - curX;
        const deltY = this._mouseY - curY;
        const scale = Math.hypot(deltY, deltX);
        if (scale < 150 && scale > 50) {
            const rad = Math.atan2(deltY, deltX) + Math.PI;
            let closest = 0;
            let closestval = 999999999;
            for (let x = 0; x < this._items.length; x++) {
                const curmin = (x / this._items.length) * 2 * Math.PI;
                if (rad - curmin < closestval && rad - curmin > 0) {
                    closestval = rad - curmin;
                    closest = x;
                }
            }
            this._closest = closest;
        } else {
            this._closest = -1;
        }
    };
    @action
    onPointerUp = (e: PointerEvent) => {
        this._mouseDown = false;
        const curX = e.clientX;
        const curY = e.clientY;
        if (this._mouseX !== curX || this._mouseY !== curY) {
            this._shouldDisplay = false;
        }
        this._shouldDisplay && (this._display = true);
        document.removeEventListener('pointermove', this.onPointerMove);
        if (this._closest !== -1 && this._items?.length > this._closest) {
            this._items[this._closest].event();
        }
    };

    @action
    closeMenu = () => {
        this.clearItems();
        this._display = false;
        this._shouldDisplay = false;
    };

    @action
    clearItems() {
        this._items = [];
    }

    previewcircle() {
        if (document.getElementById('newCanvas') !== null) {
            const c: any = document.getElementById('newCanvas');
            if (c.getContext) {
                const ctx = c.getContext('2d');
                ctx.beginPath();
                ctx.arc(150, 150, 50, 0, 2 * Math.PI);
                ctx.fillStyle = 'white';
                ctx.fill();
                ctx.font = '12px Arial';
                ctx.fillStyle = 'black';
                ctx.textAlign = 'center';
                let description = '';
                if (this._closest !== -1) {
                    description = this._items[this._closest].description;
                }
                if (description.length > 15) {
                    description = description.slice(0, 12);
                    description += '...';
                }
                ctx.fillText(description, 150, 150, 90);
            }
        }
    }

    render() {
        if (!this._display) {
            return null;
        }
        const style = this._yRelativeToTop ? { left: this._pageX - 130, top: this._pageY - 130 } : { left: this._pageX - 130, top: this._pageY - 130 };

        return (
            <div className="radialMenu-cont" onTouchStart={this.catchTouch} style={style}>
                <canvas id="newCanvas" style={{ position: 'absolute' }} height="300" width="300">
                    {' '}
                    Your browser does not support the HTML5 canvas tag.
                </canvas>
                {this.menuItems}
            </div>
        );
    }
}
