/* eslint-disable react/jsx-props-no-spreading */
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, makeObservable, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { SnappingManager } from '../util/SnappingManager';
import { UndoManager } from '../util/UndoManager';
import { ObservableReactComponent } from './ObservableReactComponent';

export interface OriginalMenuProps {
    description: string;
    event: (stuff?: any) => void;
    undoable?: boolean;
    icon?: IconProp | JSX.Element; // maybe should be optional (icon?)
    closeMenu?: () => void;
}

export interface SubmenuProps {
    description: string;
    // eslint-disable-next-line no-use-before-define
    subitems: ContextMenuProps[];
    noexpand?: boolean;
    addDivider?: boolean;
    icon: IconProp; // maybe should be optional (icon?)
    closeMenu?: () => void;
}

export type ContextMenuProps = OriginalMenuProps | SubmenuProps;

@observer
export class ContextMenuItem extends ObservableReactComponent<ContextMenuProps & { selected?: boolean }> {
    @observable private _items: Array<ContextMenuProps> = [];
    @observable private overItem = false;

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

    componentDidMount() {
        runInAction(() => {
            this._items.length = 0;
        });
        if ((this._props as SubmenuProps)?.subitems) {
            (this._props as SubmenuProps).subitems?.forEach(i => runInAction(() => this._items.push(i)));
        }
    }

    handleEvent = async (e: React.MouseEvent<HTMLDivElement>) => {
        if ('event' in this._props) {
            this._props.closeMenu?.();
            const batch = this._props.undoable !== false ? UndoManager.StartBatch(`Click Menu item: ${this._props.description}`) : undefined;
            await this._props.event({ x: e.clientX, y: e.clientY });
            batch?.end();
        }
    };

    currentTimeout?: any;
    static readonly timeout = 300;
    _overPosY = 0;
    _overPosX = 0;
    onPointerEnter = (e: React.MouseEvent) => {
        if (this.currentTimeout) {
            clearTimeout(this.currentTimeout);
            this.currentTimeout = undefined;
        }
        if (this.overItem) {
            return;
        }
        this._overPosY = e.clientY;
        this._overPosX = e.clientX;
        this.currentTimeout = setTimeout(
            action(() => {
                this.overItem = true;
            }),
            ContextMenuItem.timeout
        );
    };

    onPointerLeave = () => {
        if (this.currentTimeout) {
            clearTimeout(this.currentTimeout);
            this.currentTimeout = undefined;
        }
        if (!this.overItem) {
            return;
        }
        this.currentTimeout = setTimeout(
            action(() => {
                this.overItem = false;
            }),
            ContextMenuItem.timeout
        );
    };

    isJSXElement(val: any): val is JSX.Element {
        return React.isValidElement(val);
    }

    render() {
        if ('event' in this._props) {
            return (
                <div className={'contextMenu-item' + (this._props.selected ? ' contextMenu-itemSelected' : '')} onPointerDown={this.handleEvent}>
                    {this._props.icon ? <span className="contextMenu-item-icon-background">{this.isJSXElement(this._props.icon) ? this._props.icon : <FontAwesomeIcon icon={this._props.icon} size="sm" />}</span> : null}
                    <div className="contextMenu-description">{this._props.description.replace(':', '')}</div>
                    <div
                        className="contextMenu-item-background"
                        style={{
                            background: SnappingManager.userColor,
                        }}
                    />
                </div>
            );
        }
        if ('subitems' in this._props) {
            const where = !this.overItem ? '' : this._overPosY < window.innerHeight / 3 ? 'flex-start' : this._overPosY > (window.innerHeight * 2) / 3 ? 'flex-end' : 'center';
            const marginTop = !this.overItem ? '' : this._overPosY < window.innerHeight / 3 ? '20px' : this._overPosY > (window.innerHeight * 2) / 3 ? '-20px' : '';

            // here
            const submenu = !this.overItem ? null : (
                <div
                    className="contextMenu-subMenu-cont"
                    style={{
                        marginLeft: window.innerWidth - this._overPosX - 50 > 0 ? '90%' : '20%',
                        marginTop,
                        background: SnappingManager.userBackgroundColor,
                    }}>
                    {this._items.map(prop => (
                        <ContextMenuItem {...prop} key={prop.description} closeMenu={this._props.closeMenu} />
                    ))}
                </div>
            );
            if (!(this._props as SubmenuProps).noexpand) {
                return (
                    <div className="contextMenu-inlineMenu">
                        {this._items.map(prop => (
                            <ContextMenuItem {...prop} key={prop.description} closeMenu={this._props.closeMenu} />
                        ))}
                    </div>
                );
            }
            return (
                <div
                    className={'contextMenu-item' + (this._props.selected ? ' contextMenu-itemSelected' : '')}
                    style={{ alignItems: where, borderTop: this._props.addDivider ? 'solid 1px' : undefined }}
                    onMouseLeave={this.onPointerLeave}
                    onMouseEnter={this.onPointerEnter}>
                    {this._props.icon ? (
                        <span className="contextMenu-item-icon-background" onMouseEnter={this.onPointerLeave} style={{ alignItems: 'center', alignSelf: 'center' }}>
                            <FontAwesomeIcon icon={this._props.icon} size="sm" />
                        </span>
                    ) : null}
                    <div className="contextMenu-description" onMouseEnter={this.onPointerEnter} style={{ alignItems: 'center', alignSelf: 'center' }}>
                        {this._props.description}
                        <FontAwesomeIcon icon="angle-right" size="lg" style={{ position: 'absolute', right: '10px' }} />
                    </div>
                    <div
                        className="contextMenu-item-background"
                        style={{
                            background: SnappingManager.userColor,
                        }}
                    />
                    {submenu}
                </div>
            );
        }
        return null;
    }
}
