///////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2002-2026, Open Design Alliance (the "Alliance").
// All rights reserved.
//
// This software and its documentation and related materials are owned by
// the Alliance. The software may only be incorporated into application
// programs owned by members of the Alliance, subject to a signed
// Membership Agreement and Supplemental Software License Agreement with the
// Alliance. The structure and organization of this software are the valuable
// trade secrets of the Alliance and its suppliers. The software is also
// protected by copyright law and international treaty provisions. Application
// programs incorporating this software must include the following statement
// with their copyright notices:
//
//   This application incorporates Open Design Alliance software pursuant to a
//   license agreement with Open Design Alliance.
//   Open Design Alliance Copyright (C) 2002-2026 by Open Design Alliance.
//   All rights reserved.
//
// By use of this software, its documentation or related materials, you
// acknowledge and accept the above terms.
///////////////////////////////////////////////////////////////////////////////

import {
  Box3,
  BufferGeometry,
  Color,
  DoubleSide,
  Float32BufferAttribute,
  Mesh,
  Object3D,
  Points,
  PointsMaterial,
  ShaderMaterial,
  ShapeUtils,
  Sphere,
  Vector2,
  Vector3,
} from "three";
import { LineSegmentsGeometry } from "three/examples/jsm/lines/LineSegmentsGeometry.js";
import { LineMaterial } from "three/examples/jsm/lines/LineMaterial.js";
import { LineSegments2 } from "three/examples/jsm/lines/LineSegments2.js";

/**
 * Spatial Hash Grid class. Used for merging vertices that are practically at the same coordinate (within
 * the given tolerance). This is critical for eliminating gaps caused by floating-point precision
 * errors.
 */
class PointHashGrid {
  constructor(tolerance = 1e-5) {
    // Tolerance dictates how close two points must be to be considered identical
    this.tolerance = tolerance;

    // Array holding the actual Three.Vector3 objects
    this.points = [];

    // Map storing cell string keys to an array of point indices
    this.grid = new Map();
  }

  // Creates a unique string key based on integer cell coordinates
  _hash(hx, hy, hz) {
    return `${hx},${hy},${hz}`;
  }

  // Adds a vector to the grid, or returns the index of an existing identical vector
  add(v) {
    // Divide coordinates by tolerance and round to get integer grid coordinates
    const hx = Math.round(v.x / this.tolerance);
    const hy = Math.round(v.y / this.tolerance);
    const hz = Math.round(v.z / this.tolerance);

    // Search the current cell and all 26 adjacent cells to ensure
    // we catch points that fall exactly on cell boundaries
    for (let i = -1; i <= 1; i++) {
      for (let j = -1; j <= 1; j++) {
        for (let k = -1; k <= 1; k++) {
          // Calculate the hash key for the neighbor cell
          const hash = this._hash(hx + i, hy + j, hz + k);

          // Retrieve the cell array from the grid
          const cell = this.grid.get(hash);

          if (cell) {
            // Iterate over point IDs present in this cell
            for (const id of cell) {
              // If distance is within tolerance, it's a duplicate. Return the existing ID.
              if (this.points[id].distanceTo(v) <= this.tolerance) return id;
            }
          }
        }
      }
    }

    // If point does not exist, assign a new index based on array length
    const id = this.points.length;

    // Clone the vector to prevent reference mutations and push to array
    this.points.push(v.clone());

    // Get the hash for the central cell
    const centerHash = this._hash(hx, hy, hz);

    // Initialize an empty array for the cell if it doesn't exist
    if (!this.grid.has(centerHash)) this.grid.set(centerHash, []);

    // Push the new point ID into the respective cell
    this.grid.get(centerHash).push(id);

    return id;
  }
}

/**
 * Sections Helper Class Manages all meshes related to clipping planes: Fill (Caps), Outlines, and Debug
 * Points
 */
class SectionsHelper extends Object3D {
  constructor() {
    super();

    this.type = "SectionsHelper";

    // Configuration flags for visual settings
    this.flags = {
      fillEnabled: true,
      fillColor: "#fffde7",
      hatchEnabled: true,
      hatchColor: "#000000",
      hatchScale: 8.0,
      outlineEnabled: true,
      outlineColor: "#000000",
      outlineWidth: 2,
      boundaryOnly: true,
      showDebugSeams: false,
      showDebugPoints: false,
      showDebugSegments: false,
      showDebugGaps: false,
      showDebugInfo: false,
      useObjFillColor: false,
      useObjOutlineColor: false,
    };

    // Arrays storing corresponding meshes for each clipping plane
    this._caps = [];
    this._outlines = [];
    this._debugPoints = [];
    this._debugSegments = [];
    this._debugGaps = [];

    // Pre-allocated vectors to prevent excessive object instantiation during render loops
    this._vA = new Vector3();
    this._vB = new Vector3();
    this._vC = new Vector3();

    // Pre-allocated bounding box object
    this._worldBox = new Box3();
  }

  // Cleanup method to properly dispose of geometries and materials and free GPU memory
  dispose() {
    // Helper arrow function to dispose an individual item
    const disposeMesh = (item) => {
      if (item.geometry) item.geometry.dispose();
      if (item.material) item.material.dispose();
      this.remove(item);
    };

    // Execute cleanup for all mesh arrays
    this._caps.forEach(disposeMesh);
    this._outlines.forEach(disposeMesh);
    this._debugPoints.forEach(disposeMesh);
    this._debugSegments.forEach(disposeMesh);
    this._debugGaps.forEach(disposeMesh);

    // Clear the internal array references
    this._caps.length = 0;
    this._outlines.length = 0;
    this._debugPoints.length = 0;
    this._debugSegments.length = 0;
    this._debugGaps.length = 0;
  }

  // Update the resolution uniform for fat lines when viewport changes
  setSize(width, height) {
    this._outlines.forEach((o) => {
      if (o.material.resolution) o.material.resolution.set(width, height);
    });

    this._debugSegments.forEach((s) => {
      if (s.material.resolution) s.material.resolution.set(width, height);
    });
  }

  // Creates necessary helper meshes based on the amount of active clipping planes
  _ensureHelpersCount(count) {
    // Custom vertex shader for caps rendering
    // Extracts screen-space position into world-space format to allow steady hatch drawing
    const hatchVertexShader = `
                    #include <common>
                    #include <logdepthbuf_pars_vertex>
                    #include <clipping_planes_pars_vertex>
                    
                    attribute float aHatchDir; 
                    attribute vec3 aFillColor;
                    
                    varying vec3 vWP; 
                    varying float vHatchDir; 
                    varying vec3 vFillColor;
                    
                    void main() { 
                        vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
                        #include <clipping_planes_vertex>
                        
                        vWP = (modelMatrix * vec4(position, 1.0)).xyz;
                        vHatchDir = aHatchDir; 
                        vFillColor = aFillColor;
                        
                        gl_Position = projectionMatrix * mvPosition; 
                        #include <logdepthbuf_vertex>
                    }
                `;

    // Custom fragment shader for caps rendering
    // Uses modulo arithmetic to draw alternating hatch lines independent of zoom level
    const hatchFragmentShader = `
                    #include <common>
                    #include <logdepthbuf_pars_fragment>
                    #include <clipping_planes_pars_fragment>
                    
                    uniform vec3 lineColor; 
                    uniform float uHatchScale; 
                    uniform float uHatchEnabled;
                    
                    varying vec3 vWP; 
                    varying float vHatchDir; 
                    varying vec3 vFillColor;
                    
                    void main() { 
                        #include <clipping_planes_fragment>
                        #include <logdepthbuf_fragment>
                        
                        float v1 = mod(gl_FragCoord.x + gl_FragCoord.y, uHatchScale);
                        float v2 = mod(gl_FragCoord.x - gl_FragCoord.y, uHatchScale);
                        float v = mix(v1, v2, vHatchDir);
                        
                        float hatchMask = step(v, 1.5) * uHatchEnabled;
                        gl_FragColor = vec4(mix(vFillColor, lineColor, hatchMask), 1.0); 
                    }
                `;

    // Generate new meshes if the active plane count exceeds our pool
    while (this._caps.length < count) {
      // Cap material defining the cross-section surface
      const capMat = new ShaderMaterial({
        uniforms: {
          lineColor: { value: new Color() },
          uHatchScale: { value: 10.0 },
          uHatchEnabled: { value: 1.0 },
        },
        vertexShader: hatchVertexShader,
        fragmentShader: hatchFragmentShader,
        side: DoubleSide,
        clipping: true,
        depthTest: true,
        // STABLE LOGIC: Disabling depth write forces the fill to render,
        // but not push to Z-buffer, allowing Outline meshes (rendered later) to naturally
        // sit perfectly on top without struggling with Z-fighting.
        depthWrite: false,
      });

      const capMesh = new Mesh(new BufferGeometry(), capMat);
      // Render fills early
      capMesh.renderOrder = 5;
      this.add(capMesh);
      this._caps.push(capMesh);

      // Material for the thick intersection contour
      const lineMat = new LineMaterial({
        color: 0xffffff,
        linewidth: 2,
        resolution: new Vector2(window.innerWidth, window.innerHeight),
        depthTest: true,
        clipping: true,
        vertexColors: true,
      });

      const lineObj = new LineSegments2(new LineSegmentsGeometry(), lineMat);
      // Render outlines late so they sit atop the non-depth-writing fill mesh
      lineObj.renderOrder = 100;
      this.add(lineObj);
      this._outlines.push(lineObj);

      // Material for rendering discrete intersection points (Debugging)
      const ptsMat = new PointsMaterial({
        color: 0x00aaff,
        size: 6,
        sizeAttenuation: false,
        depthTest: false,
        transparent: true,
        depthWrite: false,
      });

      const pointsObj = new Points(new BufferGeometry(), ptsMat);
      pointsObj.renderOrder = 200;
      this.add(pointsObj);
      this._debugPoints.push(pointsObj);

      // Material for rendering discrete unconnected intersection segments (Debugging)
      const debugSegMat = new LineMaterial({
        color: 0x00ff00,
        linewidth: 4,
        resolution: new Vector2(window.innerWidth, window.innerHeight),
        depthTest: false,
        transparent: true,
        depthWrite: false,
        clipping: true,
      });

      const debugSegObj = new LineSegments2(new LineSegmentsGeometry(), debugSegMat);
      debugSegObj.renderOrder = 150;
      this.add(debugSegObj);
      this._debugSegments.push(debugSegObj);

      // Material to display failure points where loops didn't close (Debugging)
      const gapPtsMat = new PointsMaterial({
        size: 6,
        sizeAttenuation: false,
        depthTest: false,
        transparent: true,
        depthWrite: false,
        vertexColors: true,
      });

      const gapsObj = new Points(new BufferGeometry(), gapPtsMat);
      gapsObj.renderOrder = 250;
      this.add(gapsObj);
      this._debugGaps.push(gapsObj);
    }

    // If planes were disabled, hide their associated meshes from the scene
    for (let i = count; i < this._caps.length; i++) {
      this._caps[i].visible = false;
      this._outlines[i].visible = false;
      this._debugPoints[i].visible = false;
      this._debugSegments[i].visible = false;
      this._debugGaps[i].visible = false;
    }
  }

  // Main update loop processing geometry intersections
  update(objects, extents, planes) {
    const t0 = performance.now();

    // Initialize the correct amount of helper meshes
    this._ensureHelpersCount(planes.length);

    // Exit early if no planes are active
    if (planes.length === 0) return;

    // Determine mathematical bounding radius
    const sphere = extents.getBoundingSphere(new Sphere());
    const globalRadius = Math.max(sphere.radius, 1e-3);

    // Bias prevents geometry cut surfaces and generated caps from competing mathematically
    const clippingBias = globalRadius * 1e-4;

    // Prepare a slightly shifted copy of planes specifically for clipping the caps
    const biasedPlanes = planes.map((p) => {
      const bp = p.clone();
      bp.constant += clippingBias;
      return bp;
    });

    // Gather all relevant mesh objects from the scene hierarchy
    const targetMeshes = [];
    objects.forEach((obj) => {
      if (obj.isMesh && obj.material) {
        const mats = Array.isArray(obj.material) ? obj.material : [obj.material];
        if (mats.some((m) => m.clippingPlanes)) targetMeshes.push(obj);
      }
    });

    // Iterate over every active clipping plane
    planes.forEach((plane, pIdx) => {
      // Fetch corresponding helper objects
      const capMesh = this._caps[pIdx];
      const outlineMesh = this._outlines[pIdx];
      const debugPtsMesh = this._debugPoints[pIdx];
      const debugSegsMesh = this._debugSegments[pIdx];
      const debugGapsMesh = this._debugGaps[pIdx];

      // Cap shader writes the values straight into the framebuffer, so we need
      // to bypass Three.js's sRGB→linear color management and push sRGB values
      // to the GPU because the Viewer uses LinearSRGBColorSpace.
      const hatchColor = new Color(this.flags.hatchColor);
      hatchColor.convertLinearToSRGB();

      // Set uniforms
      capMesh.material.uniforms.lineColor.value.set(hatchColor);
      capMesh.material.uniforms.uHatchScale.value = this.flags.hatchScale;
      capMesh.material.uniforms.uHatchEnabled.value = this.flags.hatchEnabled ? 1.0 : 0.0;
      outlineMesh.material.linewidth = this.flags.outlineWidth;

      // Exclude current plane from array to avoid self-clipping
      const otherBiasedPlanes = biasedPlanes.filter((_, i) => i !== pIdx);

      capMesh.material.clippingPlanes = otherBiasedPlanes;
      outlineMesh.material.clippingPlanes = otherBiasedPlanes;
      debugSegsMesh.material.clippingPlanes = otherBiasedPlanes;

      // Establish 2D Local Space on the plane surface using Cross Products
      const n = plane.normal;
      const planeOrigin = n.clone().multiplyScalar(-plane.constant);

      const up = new Vector3(0, 1, 0);

      // Fallback 'up' vector if plane is completely horizontal
      if (Math.abs(n.dot(up)) > 0.999) up.set(1, 0, 0);

      // Create U and V axis vectors laying perfectly flat on the clipping plane
      const uAxis = new Vector3().crossVectors(up, n).normalize();
      const vAxis = new Vector3().crossVectors(n, uAxis).normalize();

      // Initialize arrays collecting vertex data across all intercepted meshes
      const positions = [];
      const indices = [];
      const hatchDirs = [];
      const fillColors = [];
      const combinedOutlinePoints = [];
      const combinedOutlineColors = [];
      const rawPts = [];
      const rawSegs = [];
      const rawGaps = [];
      const rawGapColors = [];

      // Scan every object in the model to see if it intercepts this plane
      targetMeshes.forEach((mesh, meshIndex) => {
        // Compute bounding structures if missing
        if (!mesh.geometry.boundingBox) mesh.geometry.computeBoundingBox();
        if (!mesh.geometry.boundingSphere) mesh.geometry.computeBoundingSphere();

        // Execute broad-phase culling
        this._worldBox.copy(mesh.geometry.boundingBox).applyMatrix4(mesh.matrixWorld);
        if (!plane.intersectsBox(this._worldBox)) return;

        // Compute contextual tolerances based on scale
        const localScale = new Vector3().setFromMatrixScale(mesh.matrixWorld);
        const maxScale = Math.max(localScale.x, localScale.y, localScale.z);
        const localRadius = Math.max(mesh.geometry.boundingSphere.radius * maxScale, 1e-3);

        // Adaptive tolerances to maintain mathematical precision
        const localHashTolerance = Math.max(localRadius * 1e-4, 1e-6);
        const localEps = Math.max(localRadius * 1e-5, 1e-7);

        // Capture object color to optionally apply to the cross section
        const baseColor = new Color(0xffffff);
        const om = mesh.userData.originalMaterial; // <- highlighted object
        const mm = om ?? (Array.isArray(mesh.material) ? mesh.material[0] : mesh.material);
        if (mm.color) baseColor.copy(mm.color);

        // Darken base colors slightly for better contrast on section faces
        const objFillColor = baseColor.clone().lerp(new Color(0x000000), 0.2);
        const objOutlineColor = baseColor.clone().lerp(new Color(0x000000), 0.85);

        // Create distinct color ID for debug views
        const hue = ((meshIndex * 137.5) % 360) / 360;
        const meshGapColor = new Color().setHSL(hue, 1.0, 0.5);

        // Alternate hatching direction index
        const currentHatchDir = meshIndex % 2 === 0 ? 0.0 : 1.0;

        // Map desired color based on user UI flag.
        const fillColor = this.flags.useObjFillColor ? objFillColor : new Color(this.flags.fillColor);
        const outlineColor = this.flags.useObjOutlineColor ? objOutlineColor : new Color(this.flags.outlineColor);

        // Cap and outline shaders write the values straight into the framebuffer, so we
        // need to bypass Three.js's sRGB→linear color management and push sRGB values
        // to the GPU because the Viewer uses LinearSRGBColorSpace.
        meshGapColor.convertLinearToSRGB();
        fillColor.convertLinearToSRGB();
        outlineColor.convertLinearToSRGB();

        // Map tracking frequency of line segments and Spatial grid for points
        const localEdgeStats = new Map();
        const localPointGrid = new PointHashGrid(localHashTolerance);

        // Gather intersections
        this._calculateMeshSegmentsUndirected(mesh, plane, localEdgeStats, localPointGrid, localEps);

        if (localEdgeStats.size > 0) {
          const boundaryEdges = [];

          // Iterate over gathered edges to find outer boundaries
          for (const [key, stat] of localEdgeStats.entries()) {
            // Segments appearing an odd number of times represent the outermost silhouette
            const isBoundary = stat.count % 2 !== 0;
            const ids = key.split("-");
            const id0 = Number(ids[0]);
            const id1 = Number(ids[1]);

            // Fetch corresponding vector structures
            const p1 = localPointGrid.points[id0];
            const p2 = localPointGrid.points[id1];

            // Determine if this edge should be pushed to the active visual outline
            if (this.flags.showDebugSeams || (this.flags.boundaryOnly ? isBoundary : true)) {
              combinedOutlinePoints.push(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);
              combinedOutlineColors.push(outlineColor.r, outlineColor.g, outlineColor.b);
              combinedOutlineColors.push(outlineColor.r, outlineColor.g, outlineColor.b);
            }

            if (isBoundary) boundaryEdges.push([id0, id1]);

            if (this.flags.showDebugSegments) rawSegs.push(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);
          }

          if (this.flags.showDebugPoints) {
            for (const p of localPointGrid.points) rawPts.push(p.x, p.y, p.z);
          }

          // If we have enough edges to form a polygon, proceed to loop-building
          if (this.flags.fillEnabled && boundaryEdges.length >= 3) {
            const currentAdj = new Map();

            // Populate adjacency map to build node-to-node relationships
            for (const edge of boundaryEdges) {
              const a = edge[0];
              const b = edge[1];
              if (!currentAdj.has(a)) currentAdj.set(a, []);
              if (!currentAdj.has(b)) currentAdj.set(b, []);
              currentAdj.get(a).push(b);
              currentAdj.get(b).push(a);
            }

            const degree1 = [];

            // Detect vertices that have only 1 neighbor (unclosed chains)
            for (const [node, neighbors] of currentAdj.entries()) {
              if (neighbors.length === 1) degree1.push(node);
            }

            const stitchTol = Math.max(localRadius * 0.05, 1e-4);

            // Attempt to auto-stitch dead ends by snapping them to the nearest valid edge
            for (let i = 0; i < degree1.length; i++) {
              const n1 = degree1[i];
              if (currentAdj.get(n1).length !== 1) continue;

              const p1 = localPointGrid.points[n1];
              let bestEdgeIdx = -1;
              let bestProj = null;
              let bestT = 0;
              let minDist = stitchTol;

              const edgeCount = boundaryEdges.length;

              for (let eIdx = 0; eIdx < edgeCount; eIdx++) {
                const edge = boundaryEdges[eIdx];
                const eA = edge[0];
                const eB = edge[1];
                if (eA === n1 || eB === n1) continue;

                const pA = localPointGrid.points[eA];
                const pB = localPointGrid.points[eB];

                const lineVec = new Vector3().subVectors(pB, pA);
                const lineLenSq = lineVec.lengthSq();

                let proj;
                let t;

                // Line Math: Find the closest projected point on the segment
                if (lineLenSq < 1e-12) {
                  proj = pA.clone();
                  t = 0;
                } else {
                  const ptVec = new Vector3().subVectors(p1, pA);
                  t = ptVec.dot(lineVec) / lineLenSq;
                  t = Math.max(0, Math.min(1, t));
                  proj = new Vector3().copy(pA).addScaledVector(lineVec, t);
                }

                const dist = p1.distanceTo(proj);

                // Track the absolute best matching candidate
                if (dist < minDist) {
                  minDist = dist;
                  bestEdgeIdx = eIdx;
                  bestProj = proj;
                  bestT = t;
                }
              }

              // If a candidate was found, merge nodes and inject into adjacency logic
              if (bestEdgeIdx !== -1) {
                const edge = boundaryEdges[bestEdgeIdx];
                const eA = edge[0];
                const eB = edge[1];

                if (bestT < 0.001) {
                  boundaryEdges.push([n1, eA]);
                  currentAdj.get(n1).push(eA);
                  currentAdj.get(eA).push(n1);
                  p1.copy(localPointGrid.points[eA]);
                } else if (bestT > 0.999) {
                  boundaryEdges.push([n1, eB]);
                  currentAdj.get(n1).push(eB);
                  currentAdj.get(eB).push(n1);
                  p1.copy(localPointGrid.points[eB]);
                } else {
                  const newNodeId = localPointGrid.add(bestProj);

                  edge[1] = newNodeId;
                  boundaryEdges.push([newNodeId, eB]);
                  boundaryEdges.push([n1, newNodeId]);

                  const neighborsA = currentAdj.get(eA);
                  neighborsA[neighborsA.indexOf(eB)] = newNodeId;

                  const neighborsB = currentAdj.get(eB);
                  neighborsB[neighborsB.indexOf(eA)] = newNodeId;

                  if (!currentAdj.has(newNodeId)) currentAdj.set(newNodeId, []);
                  currentAdj.get(newNodeId).push(eA, eB, n1);

                  currentAdj.get(n1).push(newNodeId);
                  p1.copy(bestProj);
                }
              }
            }

            // Mark still unresolved vertices for debugging purposes
            if (this.flags.showDebugGaps) {
              for (const [node, neighbors] of currentAdj.entries()) {
                if (neighbors.length !== 2) {
                  const p = localPointGrid.points[node];
                  rawGaps.push(p.x, p.y, p.z);
                  rawGapColors.push(meshGapColor.r, meshGapColor.g, meshGapColor.b);
                }
              }
            }

            // Chain edges to discover sequential closed loops
            const loops = this._assembleLoopsUndirected(boundaryEdges, localPointGrid, uAxis, vAxis);

            if (loops.length > 0) {
              // Submit valid loops for earcutting (Triangulation) to create solid geometry
              this._triangulateTreeOptimized(
                loops,
                planeOrigin,
                uAxis,
                vAxis,
                positions,
                indices,
                localRadius,
                fillColor,
                currentHatchDir,
                hatchDirs,
                fillColors
              );
            }
          }
        }
      });

      // Build and apply Fill BufferGeometry
      if (indices.length > 0) {
        capMesh.geometry.dispose();
        capMesh.geometry = new BufferGeometry();
        capMesh.geometry.setAttribute("position", new Float32BufferAttribute(positions, 3));
        capMesh.geometry.setAttribute("aHatchDir", new Float32BufferAttribute(hatchDirs, 1));
        capMesh.geometry.setAttribute("aFillColor", new Float32BufferAttribute(fillColors, 3));
        capMesh.geometry.setIndex(indices);
        capMesh.geometry.computeVertexNormals();
        capMesh.visible = this.flags.fillEnabled;
      } else {
        capMesh.visible = false;
      }

      // Build and apply Outline BufferGeometry
      if (outlineMesh.geometry) outlineMesh.geometry.dispose();
      outlineMesh.geometry = new LineSegmentsGeometry();

      if (this.flags.outlineEnabled && combinedOutlinePoints.length >= 6) {
        outlineMesh.geometry.setPositions(new Float32Array(combinedOutlinePoints));
        outlineMesh.geometry.setColors(new Float32Array(combinedOutlineColors));
        outlineMesh.visible = true;
      } else {
        outlineMesh.visible = false;
      }

      // Push Debugging visual data if toggled
      if (this.flags.showDebugPoints && rawPts.length > 0) {
        debugPtsMesh.geometry.setAttribute("position", new Float32BufferAttribute(rawPts, 3));
        debugPtsMesh.visible = true;
      } else {
        debugPtsMesh.visible = false;
      }

      if (debugSegsMesh.geometry) debugSegsMesh.geometry.dispose();
      debugSegsMesh.geometry = new LineSegmentsGeometry();

      if (this.flags.showDebugSegments && rawSegs.length >= 6) {
        debugSegsMesh.geometry.setPositions(new Float32Array(rawSegs));
        debugSegsMesh.visible = true;
      } else {
        debugSegsMesh.visible = false;
      }

      if (debugGapsMesh.geometry) debugGapsMesh.geometry.dispose();
      debugGapsMesh.geometry = new BufferGeometry();

      if (this.flags.showDebugGaps && rawGaps.length > 0) {
        debugGapsMesh.geometry.setAttribute("position", new Float32BufferAttribute(rawGaps, 3));
        debugGapsMesh.geometry.setAttribute("color", new Float32BufferAttribute(rawGapColors, 3));
        debugGapsMesh.visible = true;
      } else {
        debugGapsMesh.visible = false;
      }
    });

    if (this.flags.showDebugInfo) {
      console.log(`[SectionsHelper] v7.00 Updated in ${(performance.now() - t0).toFixed(2)} ms`);
    }
  }

  // Walks connected nodes to trace out distinct polygon paths
  _assembleLoopsUndirected(edges, pointGrid, uAxis, vAxis) {
    const adj = new Map();

    // Construct basic adjacency array list
    for (const edge of edges) {
      const a = edge[0];
      const b = edge[1];

      if (!adj.has(a)) adj.set(a, []);
      if (!adj.has(b)) adj.set(b, []);

      adj.get(a).push(b);
      adj.get(b).push(a);
    }

    const loops = [];

    // Keep resolving paths until node map is depleted
    while (adj.size > 0) {
      let startNode = -1;

      for (const key of adj.keys()) {
        if (adj.get(key).length > 0) {
          startNode = key;
          break;
        }
      }

      if (startNode === -1) break;

      let current = startNode;
      let prev = -1;
      const path = [];
      const pathIndices = new Map();

      while (true) {
        path.push(current);
        pathIndices.set(current, path.length - 1);

        const neighbors = adj.get(current);
        if (!neighbors || neighbors.length === 0) break;

        let nextIdx = 0;

        // Sharpest turn heuristic mapping for resolving complex overlapping intersections
        if (neighbors.length > 1 && prev !== -1) {
          const pPrev = pointGrid.points[prev];
          const pCurr = pointGrid.points[current];

          const vIn = new Vector3().subVectors(pCurr, pPrev);
          const in2d = new Vector2(vIn.dot(uAxis), vIn.dot(vAxis));

          if (in2d.lengthSq() > 1e-10) {
            in2d.normalize();
            let minAngle = Infinity;

            for (let i = 0; i < neighbors.length; i++) {
              const pNext = pointGrid.points[neighbors[i]];
              const vOut = new Vector3().subVectors(pNext, pCurr);
              const out2d = new Vector2(vOut.dot(uAxis), vOut.dot(vAxis));

              if (out2d.lengthSq() > 1e-10) {
                out2d.normalize();
                const angle = Math.atan2(in2d.cross(out2d), in2d.dot(out2d));

                if (angle < minAngle) {
                  minAngle = angle;
                  nextIdx = i;
                }
              }
            }
          }
        }

        const next = neighbors[nextIdx];
        neighbors.splice(nextIdx, 1);

        const nextNeighbors = adj.get(next);
        if (nextNeighbors) {
          const revIdx = nextNeighbors.indexOf(current);
          if (revIdx !== -1) nextNeighbors.splice(revIdx, 1);
        }

        prev = current;
        current = next;

        // Circular logic check - If we've seen this node before, slice out the loop
        if (pathIndices.has(current)) {
          const loopStartIdx = pathIndices.get(current);
          const loopNodes = path.slice(loopStartIdx);

          if (loopNodes.length >= 3) loops.push(loopNodes.map((id) => pointGrid.points[id]));

          for (let i = loopStartIdx; i < path.length; i++) pathIndices.delete(path[i]);

          path.length = loopStartIdx;
          prev = path.length > 1 ? path[path.length - 2] : -1;
        }
      }

      // Cleanup isolated node references
      for (const key of adj.keys()) {
        if (adj.get(key).length === 0) adj.delete(key);
      }
    }

    return loops;
  }

  // Determines hole/boundary hierarchy and triangulates accordingly via Earcut algorithm
  _triangulateTreeOptimized(
    loops,
    planeOrigin,
    uAxis,
    vAxis,
    positionsBuffer,
    indicesBuffer,
    localRadius,
    fillColor,
    hatchDir,
    hatchDirsBuffer,
    fillColorsBuffer
  ) {
    const shapesData = [];
    const minArea = localRadius * 1e-5 * (localRadius * 1e-5);

    // Reduce 3D vectors to 2D coordinates residing strictly on the cutting plane
    loops.forEach((loop) => {
      const pts2d = loop.map((p) => {
        const pv = p.clone().sub(planeOrigin);
        return new Vector2(pv.dot(uAxis), pv.dot(vAxis));
      });

      const cleaned = [];
      for (let k = 0; k < pts2d.length; k++) {
        const prev = k === 0 ? pts2d[pts2d.length - 1] : pts2d[k - 1];
        if (pts2d[k].distanceTo(prev) > 1e-5) cleaned.push(pts2d[k]);
      }
      if (cleaned.length < 3) return;

      const area = ShapeUtils.area(cleaned);

      // Bypass rendering microscopic artifacts
      if (Math.abs(area) > minArea) {
        shapesData.push({ pts2d: cleaned, absArea: Math.abs(area), depth: 0, parent: -1, holes: [] });
      }
    });

    // Largest boundaries process first
    shapesData.sort((a, b) => b.absArea - a.absArea);

    // Process Parent-Child Hierarchies
    for (let i = 0; i < shapesData.length; i++) {
      for (let j = i - 1; j >= 0; j--) {
        if (shapesData[i].absArea > shapesData[j].absArea * 0.98) continue;

        // If bounds encompass the child completely, it dictates its depth
        if (this._isLoopInside(shapesData[i].pts2d, shapesData[j].pts2d, localRadius)) {
          shapesData[i].parent = j;
          shapesData[i].depth = shapesData[j].depth + 1;
          break;
        }
      }
    }

    // Push odd depths into parent as holes
    for (let i = 0; i < shapesData.length; i++) {
      const shape = shapesData[i];
      if (shape.depth % 2 === 1 && shape.parent !== -1) {
        shapesData[shape.parent].holes.push(shape.pts2d);
      }
    }

    // Dispatch triangulation execution
    for (let i = 0; i < shapesData.length; i++) {
      const shapeData = shapesData[i];

      if (shapeData.depth % 2 !== 0) continue;

      // Reverse vertex winding order correctly
      if (ShapeUtils.area(shapeData.pts2d) < 0) {
        shapeData.pts2d.reverse();
      }

      shapeData.holes.forEach((h) => {
        if (ShapeUtils.area(h) > 0) h.reverse();
      });

      const allPoints = [...shapeData.pts2d];
      shapeData.holes.forEach((h) => allPoints.push(...h));

      const faces = ShapeUtils.triangulateShape(shapeData.pts2d, shapeData.holes);
      const vertexOffset = positionsBuffer.length / 3;

      // Extrapolate resulting 2D triangles back into absolute World 3D coordinates
      for (const pt of allPoints) {
        const p3d = planeOrigin.clone().addScaledVector(uAxis, pt.x).addScaledVector(vAxis, pt.y);

        positionsBuffer.push(p3d.x, p3d.y, p3d.z);
        hatchDirsBuffer.push(hatchDir);
        fillColorsBuffer.push(fillColor.r, fillColor.g, fillColor.b);
      }

      for (let f = 0; f < faces.length; f++) {
        indicesBuffer.push(vertexOffset + faces[f][0], vertexOffset + faces[f][1], vertexOffset + faces[f][2]);
      }
    }
  }

  // Ray-Casting algorithm for point-in-polygon checks
  _isPointInPoly(pt, poly) {
    let inside = false;
    const py = pt.y + 1.119e-7;
    const px = pt.x;

    for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
      if (
        poly[i].y > py !== poly[j].y > py &&
        px < ((poly[j].x - poly[i].x) * (py - poly[i].y)) / (poly[j].y - poly[i].y) + poly[i].x
      ) {
        inside = !inside;
      }
    }

    return inside;
  }

  // Checks whether an entire polygon resides within another
  _isLoopInside(child, parent, localRadius) {
    let minX1 = Infinity;
    let maxX1 = -Infinity;
    let minY1 = Infinity;
    let maxY1 = -Infinity;

    for (const p of child) {
      if (p.x < minX1) minX1 = p.x;
      if (p.x > maxX1) maxX1 = p.x;
      if (p.y < minY1) minY1 = p.y;
      if (p.y > maxY1) maxY1 = p.y;
    }

    let minX2 = Infinity;
    let maxX2 = -Infinity;
    let minY2 = Infinity;
    let maxY2 = -Infinity;

    for (const p of parent) {
      if (p.x < minX2) minX2 = p.x;
      if (p.x > maxX2) maxX2 = p.x;
      if (p.y < minY2) minY2 = p.y;
      if (p.y > maxY2) maxY2 = p.y;
    }

    const margin = Math.max(localRadius * 1e-4, 1e-5);

    // Box rejection filter
    if (minX1 < minX2 - margin || maxX1 > maxX2 + margin || minY1 < minY2 - margin || maxY1 > maxY2 + margin) {
      return false;
    }

    let insideCount = 0;

    // Verify actual point casting array
    for (let i = 0; i < child.length; i++) {
      if (this._isPointInPoly(child[i], parent)) {
        insideCount++;
      }
    }

    // 85% rule avoids rejecting geometry that strictly overlaps edges precisely
    return insideCount >= child.length * 0.85;
  }

  // High volume segment calculation extracting lines where geometry intercepts plane
  _calculateMeshSegmentsUndirected(mesh, plane, edgeStats, grid, eps) {
    const geom = mesh.geometry;
    const pos = geom.attributes.position;
    const index = geom.index;
    const world = mesh.matrixWorld;
    const count = index ? index.count : pos.count;

    for (let i = 0; i < count; i += 3) {
      const i1 = index ? index.getX(i) : i;
      const i2 = index ? index.getX(i + 1) : i + 1;
      const i3 = index ? index.getX(i + 2) : i + 2;

      const v1 = this._vA.fromBufferAttribute(pos, i1).applyMatrix4(world);
      const v2 = this._vB.fromBufferAttribute(pos, i2).applyMatrix4(world);
      const v3 = this._vC.fromBufferAttribute(pos, i3).applyMatrix4(world);

      let d1 = plane.distanceToPoint(v1);
      let d2 = plane.distanceToPoint(v2);
      let d3 = plane.distanceToPoint(v3);

      if (Math.abs(d1) <= eps) d1 = eps;
      if (Math.abs(d2) <= eps) d2 = eps;
      if (Math.abs(d3) <= eps) d3 = eps;

      const s1 = d1 > 0 ? 1 : -1;
      const s2 = d2 > 0 ? 1 : -1;
      const s3 = d3 > 0 ? 1 : -1;

      // Discard entirely invisible triangles naturally bypassed by the plane
      if (s1 === s2 && s2 === s3) continue;

      const intersections = [];

      if (s1 !== s2) {
        intersections.push(new Vector3().lerpVectors(v1, v2, Math.abs(d1) / (Math.abs(d1) + Math.abs(d2))));
      }
      if (s2 !== s3) {
        intersections.push(new Vector3().lerpVectors(v2, v3, Math.abs(d2) / (Math.abs(d2) + Math.abs(d3))));
      }
      if (s3 !== s1) {
        intersections.push(new Vector3().lerpVectors(v3, v1, Math.abs(d3) / (Math.abs(d3) + Math.abs(d1))));
      }

      if (intersections.length >= 2) {
        const id1 = grid.add(intersections[0]);
        const id2 = grid.add(intersections[1]);

        if (id1 !== id2) {
          const key = id1 < id2 ? `${id1}-${id2}` : `${id2}-${id1}`;
          const stat = edgeStats.get(key) || { count: 0 };
          stat.count++;
          edgeStats.set(key, stat);
        }
      }
    }
  }
}

export { SectionsHelper };
