import { GSplatManager } from './gsplat-manager.js';

class GSplatLayerData {
		constructor(device, director, layer, cameraNode){
				this.gsplatManager = new GSplatManager(device, director, layer, cameraNode);
		}
		destroy() {
				this.gsplatManager.destroy();
		}
}
class GSplatCameraData {
		destroy() {
				this.layersMap.forEach((layerData)=>layerData.destroy());
				this.layersMap.clear();
		}
		removeLayerData(layer) {
				const layerData = this.layersMap.get(layer);
				if (layerData) {
						layerData.destroy();
						this.layersMap.delete(layer);
				}
		}
		getLayerData(device, director, layer, cameraNode) {
				let layerData = this.layersMap.get(layer);
				if (!layerData) {
						layerData = new GSplatLayerData(device, director, layer, cameraNode);
						this.layersMap.set(layer, layerData);
				}
				return layerData;
		}
		constructor(){
				this.layersMap = new Map();
		}
}
class GSplatDirector {
		constructor(device, scene, assetLoader){
				this.camerasMap = new Map();
				this.octrees = new Map();
				this.device = device;
				this.assetLoader = assetLoader;
				this.scene = scene;
		}
		getCameraData(camera) {
				let cameraData = this.camerasMap.get(camera);
				if (!cameraData) {
						cameraData = new GSplatCameraData();
						this.camerasMap.set(camera, cameraData);
				}
				return cameraData;
		}
		update(comp) {
				this.camerasMap.forEach((cameraData, camera)=>{
						if (!comp.camerasSet.has(camera)) {
								cameraData.destroy();
								this.camerasMap.delete(camera);
						} else {
								cameraData.layersMap.forEach((layerData, layer)=>{
										if (!camera.layersSet.has(layer.id) || !layer.enabled) {
												layerData.destroy();
												cameraData.layersMap.delete(layer);
										}
								});
						}
				});
				const camerasComponents = comp.cameras;
				for(let i = 0; i < camerasComponents.length; i++){
						const camera = camerasComponents[i].camera;
						let cameraData = this.camerasMap.get(camera);
						const layerIds = camera.layers;
						for(let j = 0; j < layerIds.length; j++){
								const layer = comp.getLayerById(layerIds[j]);
								if (layer?.enabled) {
										if (layer.gsplatPlacementsDirty || !cameraData) {
												const placements = layer.gsplatPlacements;
												if (placements.length === 0) {
														if (cameraData) {
																cameraData.removeLayerData(layer);
														}
												} else {
														cameraData ??= this.getCameraData(camera);
														const layerData = cameraData.getLayerData(this.device, this, layer, camera.node);
														layerData.gsplatManager.reconcile(placements);
												}
										}
								}
						}
						cameraData?.layersMap.forEach((layerData)=>{
								layerData.gsplatManager.update(this.scene);
						});
				}
				for(let i = 0; i < comp.layerList.length; i++){
						comp.layerList[i].gsplatPlacementsDirty = false;
				}
		}
}

export { GSplatDirector };
