/**
 * Reine Three.js Dispose-Helpers für den cleanup-Pfad.
 *
 * Three.js' `material.dispose()` gibt **Texturen nicht** automatisch frei — CanvasTexturen
 * (Achsenbeschriftungen, Gradient-/Grid-Hintergründe, Schatten, Legenden-Maps) müssen wir
 * manuell disposen. Sonst akkumuliert GPU-Speicher pro Chart dauerhaft.
 *
 * `disposeSceneGeometriesAndMaterials` traversiert die Scene und disposet:
 *   • `obj.geometry`
 *   • alle Texturen aller Materialien (über `disposeMaterialTextures`)
 *   • die Materialien selbst
 *   • Ruler-Tick-Zusatztexturen (`userData._mapRight`, `_mapCenter`)
 *   • `userData._rulerMaterials`, `_rulerMaterialsIntermediate`
 */
const TEXTURE_MATERIAL_KEYS = [
  'map', 'alphaMap', 'aoMap', 'bumpMap', 'displacementMap', 'emissiveMap',
  'envMap', 'lightMap', 'metalnessMap', 'normalMap', 'roughnessMap',
  'specularMap', 'matcap', 'gradientMap', 'clearcoatMap', 'clearcoatNormalMap',
  'clearcoatRoughnessMap', 'sheenColorMap', 'sheenRoughnessMap', 'transmissionMap',
  'thicknessMap', 'iridescenceMap', 'iridescenceThicknessMap',
];

export function disposeMaterialTextures(mat) {
  if (!mat) return;
  for (let k = 0; k < TEXTURE_MATERIAL_KEYS.length; k++) {
    const key = TEXTURE_MATERIAL_KEYS[k];
    const tex = mat[key];
    if (tex && typeof tex.dispose === 'function') {
      tex.dispose();
      mat[key] = null;
    }
  }
}

export function disposeSceneGeometriesAndMaterials(scene) {
  scene.traverse((obj) => {
    if (obj.geometry) obj.geometry.dispose();
    if (obj.material) {
      const mats = Array.isArray(obj.material) ? obj.material : [obj.material];
      mats.forEach((m) => { disposeMaterialTextures(m); m.dispose(); });
    }
    /* Ruler-Tick-Labels halten Extra-Texturen in userData (`_mapRight`, `_mapCenter`) — `material.map`
       zeigt jeweils nur auf eine davon; die andere würde ohne expliziten Dispose leaken. */
    const ud = obj.userData;
    if (ud) {
      if (ud._mapRight && typeof ud._mapRight.dispose === 'function') { ud._mapRight.dispose(); ud._mapRight = null; }
      if (ud._mapCenter && typeof ud._mapCenter.dispose === 'function') { ud._mapCenter.dispose(); ud._mapCenter = null; }
    }
    if (ud?._rulerMaterials) ud._rulerMaterials.forEach((m) => { disposeMaterialTextures(m); m.dispose(); });
    if (ud?._rulerMaterialsIntermediate) ud._rulerMaterialsIntermediate.forEach((m) => { disposeMaterialTextures(m); m.dispose(); });
  });
}

/** Reflector hält intern einen 2048×2048 WebGLRenderTarget, der nur über seine eigene
 *  `dispose()`-Methode freigegeben wird — `material.dispose()` reicht nicht. */
export function disposeReflector(reflector) {
  if (reflector && typeof reflector.dispose === 'function') {
    try { reflector.dispose(); } catch (_) { /* ignore */ }
  }
}
