<template>
    <v-navigation-drawer width="133">
        <v-btn-toggle variant="tonal" density="comfortable" class="ma-3" v-model="renderType" color="light-blue-darken-4">
            <v-btn value="ST" icon="mdi-video-3d-variant"></v-btn>
            <v-btn value="VR" icon="mdi-google-cardboard"></v-btn>
            <v-btn value="AG" icon="mdi-glasses"></v-btn>
        </v-btn-toggle>
        <v-btn-toggle variant="tonal" density="comfortable" class="ma-3" v-model="mode" color="green-darken-4">
            <v-btn class="text-none" value="translate" icon="mdi-cursor-move"></v-btn>
            <v-btn class="text-none" value="rotate" icon="mdi-rotate-orbit"></v-btn>
            <v-btn class="text-none" value="scale" icon="mdi-resize"></v-btn>
        </v-btn-toggle>
        <v-btn-toggle variant="tonal" v-model="cameraType" class="ma-3" density="comfortable" color="orange-darken-4">
            <v-btn value="perspective" icon="mdi-cone"></v-btn>
            <v-btn value="orthographic" icon="mdi-cone-off"></v-btn>
        </v-btn-toggle>
    </v-navigation-drawer>
    <div class="container my-3 position-relative game-designer-canvas">
        <div ref="target" @click="targetClick" @pointerdown="targetPointerDown"></div>
        <div class="renderer-gizmo"></div>
    </div>
    <v-toolbar density="compact">
        <v-slide-group show-arrows>
            <v-slide-group-item v-for="(a, i) in objectAnimations" :key="i" v-slot="{ isSelected }">
                <v-btn :color="isSelected ? 'primary' : undefined" class="ma-2"
                    :prepend-icon="'mdi-' + (a.playing ? 'stop' : 'play')" rounded @click="toggleAnimation(a)">
                    {{ a.name }}
                </v-btn>
            </v-slide-group-item>
        </v-slide-group>
    </v-toolbar>
    <v-navigation-drawer location="right">
        <v-list v-model:selected="scenesList" selectable color="primary">
            <v-list-item v-for="(s, i) in scenes" :key="i" :title="s.data.title" :value="s"></v-list-item>
        </v-list>
        <v-list selectable v-model:selected="objectsList" color="secondary">
            <v-list-item v-for="(v, k) in sceneObjects" :title="v.__title" :subtitle="k" :value=v>
                <template v-slot:prepend>
                    <v-btn variant="plain" density="comfortable" size="small" v-if="v.__o"
                        :icon="`mdi-eye${v.__o.visible ? '' : '-off'}`"
                        @click.stop="v.__o.visible = !v.__o.visible"></v-btn>
                    <!-- <v-icon :icon="components[item.name].icon" size="small"></v-icon> -->
                </template>
            </v-list-item>
        </v-list>
    </v-navigation-drawer>
</template>

<script>

import { GameEngine } from '@/lib/GameEngine';

let gameEngine = null;

export default {
    props:{
        modelValue: Object,
    },
    data(){
        return {
            scenesList: [],
            objectsList: [],
            mode: 'translate',
            pointerDownTime: 0,
            scenario: null,
            renderType: 'ST',
            cameraType: 'perspective'
        }
    },
    computed:{
        scenes(){
            return this.scenario?.scenes || [];
        },
        scene(){
            return this.scenesList[0];
        },
        currentObject(){
            return this.objectsList[0];
        },
        sceneObjects(){
            return this.object.scenes?.[this.scene?.data?.id]?.objects;
        },
        object(){
            return this.modelValue;
        },
        objectAnimations(){
            return this.currentObject?.__g?.animations?.map(a => ({
                name: a.name, id: a.uuid, a
            }));
        }
    },
    watch:{
        async scene(n){
            this.object.scenes = this.object.scenes || {}
            this.object.scenes[n.data.id] = this.object.scenes[n.data.id] || {}
            await this.loadEnvironment(n, this.object.scenes[n.data.id]);
        },
        mode(n){
            gameEngine.transformControls.setMode(n)
        },
        async 'object.scenario'(n){
            await this.loadScenario()
        },
        currentObject(n){
            gameEngine.transformControls.attach(n.__o);
            gameEngine.gizmo.target = n.__o.position;
            //gameEngine.camera.lookAt(n.__o.position)
            gameEngine.camera.updateProjectionMatrix()
        },
        renderType(v){
            gameEngine.renderType = v;
        },
        cameraType(v){
            if (v == 'perspective'){
                gameEngine.setCameraPerspective();
            }else{
                gameEngine.setCameraOrthographic();
            }
        }
    },
    async mounted(){
        gameEngine = new GameEngine();
        //this.gameEngine = gameEngine;
        await gameEngine.init(this.$refs.target, {gizmo: true});
        gameEngine.scene.add(gameEngine.transformControls.getHelper());
        gameEngine.scene.add(new gameEngine.$.GridHelper(100,100));
        this.resize();
        //gameEngine.setCamera(gameEngine.orthographicCamera)
        //gameEngine.setCameraOrthographic();
        await this.loadScenario();
        window.addEventListener('resize', this.resize);
    },
    unmounted(){
        window.removeEventListener('resize', this.resize);
        gameEngine.stop();
    },
    methods:{
        async loadScenario(){
            if (this.object.scenario){
                this.scenario = (await this.$api.scenario.load(this.object.scenario)).data;
            }else{
                this.scenario = null;
            }
        },

        /**
         * loads all environment objects
         * @param scene Scene object from the Scenario Module
         * @param target Target scene definition from Game Module
         */
        async loadEnvironment(scene, target){
            //await gameEngine.loadPanorama(`/asset/default/43.webp`);
            gameEngine.activeObjects.clear();
            await this.expandScenarioData(scene);
            target.objects = target.objects || {};
            let l = target.objects;
            if (this.scene.data.$environment.type == 'panorama2d'){
                await gameEngine.loadPanorama(`/asset/default/${this.scene.data.$environment.asset.name}`);
            }else{
                let env = await gameEngine.load(`/asset/default/${this.scene.data.$environment.asset.name}`);
                this.setObjectAttributes(l, this.scene.data, env, 100);
                gameEngine.activeObjects.add(env.scene);
            }
            for (let i of this.scene.data.items || []) {
                let gltf = await gameEngine.load(`/asset/default/${i.data.$go.asset.name}`);
                this.setObjectAttributes(l, i.data, gltf, 1);
                gameEngine.activeObjects.add(gltf.scene);
                //console.log(JSON.stringify(l));
                //window.gameEngine = gameEngine;
                //console.log(new gameEngine.$.Euler({"isEuler":true,"_x":0,"_y":0,"_z":0,"_order":"XYZ"}));
            }
            // let camera = new gameEngine.$.PerspectiveCamera();
            // let cameraHelper = new gameEngine.$.CameraHelper(camera);
            // gameEngine.activeObjects.add(cameraHelper);
            // gameEngine.activeObjects.add(camera);
            // this.setObjectAttributes(l, { id: 'camera', 'title': 'Main camera' }, { scene: camera })
            // cameraHelper.update();

            //this is needed cause when mounted canvas has different size
            this.resize();
        },
        async expandScenarioData(scene){
            scene.data.$environment = (await this.$api.gameObject.load(scene.data.environment)).data
            for (let i of scene.data.items || []) {
                i.data.$go = (await this.$api.gameObject.load(i.data.go)).data;
            }
        },
        targetPointerDown(){
            this.pointerDownTime = performance.now();
        },
        targetClick(e){
            if (performance.now() - this.pointerDownTime < 200){
                let intersects = gameEngine.intersect(e, this.$refs.target, gameEngine.activeObjects.children, true);
                //console.log(intersects)
                if (intersects.length){
                    //console.log('attaching controls to', intersects[0].object)
                    //gameEngine.transformControls.attach(intersects[0].object);
                    console.log(this.sceneObjects[intersects[0].object.__pn_id])
                    this.objectsList[0] = this.sceneObjects[intersects[0].object.__pn_id]
                }else{
                    gameEngine.transformControls.detach();
                }
            }
        },
        setObjectAttributes(l, data, o, autoScaleFactor = 1){
            if (l[data.id]){
                ['position', 'scale', 'rotation'].forEach(p=>{
                    o.scene[p].copy(l[data.id][p])
                })
            }else{
                gameEngine.autoScale(o.scene, autoScaleFactor);
            }
            l[data.id] = l[data.id] || {};
            ['position', 'scale', 'rotation', 'visible'].forEach(p=>{
                l[data.id][p] = o.scene[p];
            })
            l[data.id].__o = o.scene;
            l[data.id].__g = o;
            l[data.id].__title = data.title;
            o.scene.__pn_id = data.id;
        },
        async toggleAnimation(animation){
            animation.playing = !animation.playing;
            gameEngine.playAnimation(gameEngine.scene, animation.a, animation.playing);
        },
        resize(){
            let r = this.$refs.target;
            gameEngine.resize(r.clientWidth, r.clientHeight);
            //this.zoom = Math.min(r.clientWidth / this.viewBox.w, r.clientHeight / this.viewBox.h);
        },
    }
}
</script>