import * as THREE from 'three'
import { loadGltf } from './loadgltf.js'

export default class LevelLoader {
    constructor(inGame) {
        this.game = inGame
    }
    async load(levelData) {    
        let instancedMeshes = []
        for(let i = 0; i < levelData.models.length; i++) {
            let count = levelData.tiles.reduce((count, tile) => {
                if (tile.model == i) {
                    return ++count
                } else {
                    return count
                }
            }, 0)

            if(count == 0) {
                console.warn(`model ${levelData.models[i]} at index ${i} not used.`)
                continue
            }
            let model = levelData.models[i]
            const tileMeshScene = await loadGltf(this.game, model)
            let firstMesh
            tileMeshScene.traverse((child) => {
                if (child.isMesh) {
                    firstMesh = child
                    return
                }
            })
        
            const tileMesh = new THREE.InstancedMesh(firstMesh.geometry, firstMesh.material, count)
            tileMesh.receiveShadow = true
            instancedMeshes[i] = tileMesh
        }
    
        const matrix = new THREE.Matrix4()
        levelData.models.forEach((model, modelIndex) => {
            levelData.tiles.filter(tile => tile.model == modelIndex).forEach((tile, tileIndex) => {
                const position = new THREE.Vector3(tile.position[0] * 4, tile.position[1], tile.position[2] * 4)
                const quaternion = new THREE.Quaternion()
                quaternion.setFromAxisAngle(THREE.Object3D.DEFAULT_UP, tile.rotation)
                const scale = new THREE.Vector3(1, 1, 1)
                matrix.compose(position, quaternion, scale)
                instancedMeshes[modelIndex].setMatrixAt(tileIndex, matrix)
            })
        })

        levelData.meta.shadow.forEach(modelIndex => {
            if(instancedMeshes[modelIndex]) {
                instancedMeshes[modelIndex].castShadow = true
                instancedMeshes[modelIndex].receiveShadow = true
            }
        })

        return instancedMeshes
    }
}