import * as THREE from "three";

function disposeMaterialTextures(material: THREE.Material, disposedTextures: Set<THREE.Texture>) {
  for (const value of Object.values(material)) {
    if (value instanceof THREE.Texture && !disposedTextures.has(value)) {
      disposedTextures.add(value);
      value.dispose();
    }
  }
}

export function disposeSceneResources(root: THREE.Object3D) {
  const disposedGeometries = new Set<THREE.BufferGeometry>();
  const disposedMaterials = new Set<THREE.Material>();
  const disposedTextures = new Set<THREE.Texture>();

  root.traverse((object) => {
    const mesh = object as THREE.Mesh;
    const geometry = mesh.geometry;
    if (geometry instanceof THREE.BufferGeometry && !disposedGeometries.has(geometry)) {
      disposedGeometries.add(geometry);
      geometry.dispose();
    }

    const material = mesh.material;
    const materials = Array.isArray(material) ? material : material ? [material] : [];
    for (const candidate of materials) {
      if (candidate instanceof THREE.Material && !disposedMaterials.has(candidate)) {
        disposedMaterials.add(candidate);
        disposeMaterialTextures(candidate, disposedTextures);
        candidate.dispose();
      }
    }
  });
}
