import { makeAutoObservable } from "mobx";
import { state } from "./rootState";
import type { ReactNode } from "react";
import { IconRun, IconTrash, IconPlus, IconCubePlus, IconCubeOff } from '@tabler/icons-react';

export type MenuNodeAction = {
    id: string;
    content: ReactNode;
    tooltip: string;
    onClick: () => void;
}

export type MenuNode = {
    id: string;
    title: ReactNode;
    className?: string;
    actions?: MenuNodeAction[];
    onClick?: () => void;
    selected?: () => boolean;
    children?: MenuNode[];
}

export class MenuState {
    constructor() {
        makeAutoObservable(this);
    }

    private get editorObjectTypesMenu(): MenuNode[] {
        const editor = state.worldEditor;
        const scene = editor.scene;

        return Object.values(state.world.data.objectTypes)
            .map((ot) => {
                const children = Object.values(scene.objects)
                    .filter((o) => o.typeId === ot.id)
                    .map((o, idx) => {
                        const isPlayer = scene.playerObjectId === o.id;

                        const actions: MenuNodeAction[] = [];
                        if (!isPlayer) {
                            actions.push({
                                id: 'delete-object-instance',
                                content: <IconTrash size="1em" />,
                                tooltip: 'Delete the object',
                                onClick: () => { editor.deleteObject(o.id); },
                            });
                            actions.push({
                                id: 'control-object-instance-by-player',
                                content: <IconRun size="1em" />,
                                tooltip: 'Mark as player',
                                onClick: () => { scene.playerObjectId = o.id; },
                            });
                        }

                        return {
                            id: `o-${o.id}`,
                            title: <>
                                {isPlayer && <IconRun size="1em" />}
                                {`${ot.name} ${idx + 1}`}
                            </>,
                            className: isPlayer ? 'player-controlled-object' : undefined,
                            actions,
                            onClick: () => { state.worldEditor.setSelectedObject({ id: o.id, editMode: 'translate' }) },
                            selected: () => state.worldEditor.selection?.type === 'object' && state.worldEditor.selection?.id === o.id,
                        } as MenuNode;
                    });

                return {
                    id: `ot-${ot.id}`,
                    title: `${ot.name} (${children.length ? children.length : 'no'} instance${children.length != 1 ? 's' : ''})`,
                    actions: [
                        {
                            id: 'create-object-instance',
                            content: <IconPlus size="1em" />,
                            tooltip: 'Create new object instance',
                            onClick: () => { editor.addObjectInstanceAtRandomPosition(ot.id); },
                        },
                        {
                            id: 'delete-object-type',
                            content: <IconCubeOff size="1em" />,
                            tooltip: 'Delete object type',
                            onClick: () => { editor.deleteObjectType(ot.id); },
                        },
                    ],
                    onClick: () => { editor.setSelectedObjectType({ id: ot.id, editMode: 'scripts' }) },
                    selected: () => editor.selection?.type === 'objectType' && editor.selection?.id === ot.id,
                    children,
                } as MenuNode
            });
    }

    private get editorMenu(): MenuNode[] {
        return [
            {
                id: 'editor-scene-menu',
                title: 'Scene',
                onClick: () => { state.worldEditor.resetSelection() },
                selected: () => !state.worldEditor.selection,
                children: this.editorObjectTypesMenu,
                actions: [{
                    id: 'create-object-type',
                    content: <IconCubePlus size="1em" />,
                    tooltip: 'Create new object type',
                    onClick: () => { state.worldEditor.addObjectType(); },
                }],
            }
        ]
    }

    public get nodes(): MenuNode[] {
        return [
            ...this.editorMenu,
        ]
    }

    public nodeContainsSelected(node: MenuNode): boolean {
        return !!(node.selected?.() || node.children?.some((child) => this.nodeContainsSelected(child)));
    }

}
