import {DiagramEvent, DiagramEventType} from "./types/diagramEntity";
import {AbstractMesh, ActionEvent, Observable, Scene, Vector3, WebXRInputSource} from "@babylonjs/core";
import {InputTextView} from "../information/inputTextView";
import {DefaultScene} from "../defaultScene";
import {ControllerEvent, ControllerEventType, Controllers} from "../controllers/controllers";
import log from "loglevel";
import {Toolbox} from "../toolbox/toolbox";
import {ClickMenu} from "../menus/clickMenu";
import {ConfigMenu} from "../menus/configMenu";
import {AppConfig} from "../util/appConfig";
import {DiagramEventObserverMask} from "./types/diagramEventObserverMask";
import {ConnectionPreview} from "../menus/connectionPreview";
import {ScaleMenu2} from "../menus/ScaleMenu2";
import {viewOnly} from "../util/functions/getPath";
import {GroupMenu} from "../menus/groupMenu";


export class DiagramMenuManager {
    public readonly toolbox: Toolbox;
    public readonly scaleMenu: ScaleMenu2;
    public readonly configMenu: ConfigMenu;
    private readonly _notifier: Observable<DiagramEvent>;
    private readonly _inputTextView: InputTextView;
    private _groupMenu: GroupMenu;
    private readonly _scene: Scene;
    private _logger = log.getLogger('DiagramMenuManager');
    private _connectionPreview: ConnectionPreview;

    constructor(notifier: Observable<DiagramEvent>, controllers: Controllers, config: AppConfig, readyObservable: Observable<boolean>) {
        this._scene = DefaultScene.Scene;
        this._notifier = notifier;
        this._inputTextView = new InputTextView(controllers);
        this.configMenu = new ConfigMenu(config);

        this._inputTextView.onTextObservable.add((evt) => {
            const event = {type: DiagramEventType.MODIFY, entity: {id: evt.id, text: evt.text}}
            this._notifier.notifyObservers(event, DiagramEventObserverMask.FROM_DB);
        });
        this.toolbox = new Toolbox(readyObservable);
        this.scaleMenu = new ScaleMenu2(this._notifier);
        if (viewOnly()) {
            this.toolbox.handleMesh.setEnabled(false);
            //this.scaleMenu.handleMesh.setEnabled(false)
            this.configMenu.handleTransformNode.setEnabled(false);
        }
        controllers.controllerObservable.add((event: ControllerEvent) => {
            if (event.type == ControllerEventType.B_BUTTON) {
                if (event.value > .8) {
                    const platform = this._scene.getMeshByName("platform");

                    if (!platform) {
                        return;
                    }
                    const cameraPos = this._scene.activeCamera.globalPosition;
                    const localCamera = Vector3.TransformCoordinates(cameraPos, platform.getWorldMatrix());
                    const toolY = this.toolbox.handleMesh.absolutePosition.y;
                    if (toolY > (cameraPos.y - .2)) {
                        this.toolbox.handleMesh.position.y = localCamera.y - .2;
                    }

                    const inputY = this._inputTextView.handleMesh.absolutePosition.y;
                    if (inputY > (cameraPos.y - .2)) {
                        this._inputTextView.handleMesh.position.y = localCamera.y - .2;
                    }
                    const configY = this._inputTextView.handleMesh.absolutePosition.y;
                    if (configY > (cameraPos.y - .2)) {
                        this.configMenu.handleTransformNode.position.y = localCamera.y - .2;
                    }
                }
            }
        });
    }

    public get connectionPreview(): ConnectionPreview {
        return this._connectionPreview;
    }

    public connect(mesh: AbstractMesh) {
        if (this._connectionPreview) {
            this._connectionPreview.connect(mesh);
            this._connectionPreview = null;
        }
    }

    public editText(mesh: AbstractMesh) {
        this._inputTextView.show(mesh);
    }

    public createClickMenu(mesh: AbstractMesh, input: WebXRInputSource): ClickMenu {
        const clickMenu = new ClickMenu(mesh);
        clickMenu.onClickMenuObservable.add((evt: ActionEvent) => {
            this._logger.debug(evt);

            switch (evt.source.id) {
                case "remove":
                    this.notifyAll({type: DiagramEventType.REMOVE, entity: {id: clickMenu.mesh.id}});
                    break;
                case "label":
                    this.editText(clickMenu.mesh);
                    break;
                case "connect":
                    this._connectionPreview = new ConnectionPreview(clickMenu.mesh.id, input, evt.additionalData.pickedPoint, this._notifier);
                    break;
                case "size":
                    this.scaleMenu.show(clickMenu.mesh);
                    break;
                case "group":
                    this._groupMenu = new GroupMenu(clickMenu.mesh);
                    break;
                case "close":
                    this.scaleMenu.hide();
                    break;
            }
            this._logger.debug(evt);

        }, -1, false, this, false);

        return clickMenu;
    }

    private notifyAll(event: DiagramEvent) {
        this._notifier.notifyObservers(event, DiagramEventObserverMask.ALL);
    }
}