import { Box3, BufferGeometry, type Color, type Material, Mesh, type Raycaster, Vector3 } from "three";
import { type LineMaterial } from "three/examples/jsm/Addons";
import { type BufferElement } from "../..";
import type { WorkerThreadPool } from "../worker/base/worker-pool";
/**
 * Special alpha value to mark selected vertices for fast outline detection.
 * The AlphaSelectionOutlinePass detects this value with ZERO extra render passes.
 */
export declare const SELECTION_ALPHA = 0.99;
export declare class ViralBatchedMesh extends Mesh {
    private static readonly _tempVec3A;
    private static readonly _tempBox3A;
    globalMaterialIndex: number;
    private workerPool;
    private _depthPrePassMesh;
    constructor(geometry?: BufferGeometry, material?: Material, workerPool?: WorkerThreadPool | null);
    raycast(raycaster: Raycaster, intersects: any[]): void;
    /**
     * *for tracking and manage element visibility, for instance hide object
     */
    _bufferElements: BufferElement[];
    protected _colors: Float32Array | null;
    protected _originalColor: Color | null;
    /**
     * Stores mapping of model IDs to their element data.
     */
    protected _elementMap: Map<string, Map<string, {
        /** Start index of the element in the buffer */
        start: number;
        /** Number of vertices associated with the element */
        count: number;
        indices: number[];
    }[]>>;
    addBufferElements(bufferElements: BufferElement[], materialColor: Color): void;
    rebuildGeometry(bufferElements: BufferElement[]): void;
    protected _isBatching: boolean;
    get isBatching(): boolean;
    batch(newBufferElements: BufferElement[]): void;
    private _batchQueue;
    private _isProcessingQueue;
    batchAsync(newBufferElements: BufferElement[]): Promise<void>;
    private _processQueue;
    private _performSingleBatch;
    private _applyWorkerResult;
    /**
     * Finalize geometry after batch operation
     */
    private _finalizeGeometry;
    /**
     * get bufferEleemnts from given ids
     * @param elements
     * @returns
     */
    getElements(elements: {
        modelId: string;
        elementId: string;
    }[]): BufferElement[];
    getElementsByModel(modelIndex: number): BufferElement[];
    private _edgeLines;
    private _edgeRanges;
    private _edgeThreshold;
    private _edgeMaterial;
    enableEdgePerElement(material: LineMaterial, thresholdDeg?: number): void;
    disableEdge(): void;
    enableEdge(): void;
    /** call this after rebuild/batch to keep edges in sync (if enabled) */
    refreshEdgesIfAny(): void;
    private _buildMergedEdges;
    /** Show edges ONLY for the given elements */
    isolateEdge(elements?: {
        modelId: string;
        elementId: string;
    }[]): void;
    /** Hide edges for the given elements (keep all others) */
    hideEdge(elements?: {
        modelId: string;
        elementId: string;
    }[]): void;
    /** Restore all edges */
    edgeReset(): void;
    protected _selectedElements: {
        modelId: string;
        elementId: string;
    }[];
    protected _hidingElements: {
        modelId: string;
        elementId: string;
    }[];
    protected _isolatingElements: {
        modelId: string;
        elementId: string;
    }[];
    private _hiddenSet;
    private _isolatedSet;
    private _elementOpacityMap;
    private _isRGBAMode;
    private _elementOriginalColors;
    private _temporaryColors;
    private _ghostColors;
    /**
     * Select elements (highlights them with accent color)
     */
    select(elements: {
        modelId: string;
        elementId: string;
    }[], excepts?: {
        elements: {
            modelId: string;
            elementId: string;
        }[];
        color: {
            r: number;
            g: number;
            b: number;
        };
    }[]): void;
    get selectedElements(): {
        modelId: string;
        elementId: string;
    }[];
    get hidingElements(): {
        modelId: string;
        elementId: string;
    }[];
    get isolatingElements(): {
        modelId: string;
        elementId: string;
    }[];
    unselect(): void;
    /**
     * Set alpha value for elements (used for selection marking)
     * This is VERY fast - only updates alpha channel, no geometry copying
     *
     * When setting alpha to 1.0 (removing selection), respects hidden/isolated state
     */
    private _setSelectionAlpha;
    /**
     * Hide elements by setting their alpha to 0 (GPU-accelerated)
     * Hidden elements are discarded in fragment shader - no rendering cost
     *
     * @param elements - Elements to hide (defaults to selected elements)
     */
    hide(elements?: {
        modelId: string;
        elementId: string;
    }[]): void;
    /**
     * Isolate elements - show ONLY these elements, hide everything else
     *
     * @param elements - Elements to isolate (defaults to selected elements)
     * @returns The isolated elements
     */
    isolate(elements?: {
        modelId: string;
        elementId: string;
    }[]): {
        modelId: string;
        elementId: string;
    }[];
    /**
     * Isolate entire models
     * @param modelIds - Model IDs to isolate
     */
    isolateModel(modelIds: string[]): void;
    /**
     * Show a previously hidden element
     * @param elements - Elements to show
     */
    show(elements: {
        modelId: string;
        elementId: string;
    }[]): void;
    /**
     * Reset all visibility - show everything
     */
    reset(): void;
    /**
     * Check if an element is currently visible
     */
    isElementVisible(modelId: string, elementId: string): boolean;
    /**
     * Set opacity for specific elements (0.0 = invisible, 1.0 = fully opaque)
     * Uses custom shader's per-vertex alpha support
     *
     * @param elements - Elements to modify
     * @param opacity - Opacity value (0.0 to 1.0)
     *
     * @example
     * ```typescript
     * // Semi-transparent (ghost mode)
     * mesh.setElementOpacity([{ modelId: "0", elementId: "abc" }], 0.3);
     *
     * // Fully hidden but still raycastable
     * mesh.setElementOpacity([{ modelId: "0", elementId: "abc" }], 0.0);
     * ```
     */
    setElementOpacity(elements: {
        modelId: string;
        elementId: string;
    }[], opacity: number): void;
    /**
     * Get the current opacity of an element
     */
    getElementOpacity(modelId: string, elementId: string): number;
    /**
     * Ghost mode - semi-transparent with optional desaturation or custom color
     * Perfect for showing context while highlighting other elements
     *
     * @param elements - Elements to ghost
     * @param ghostOpacity - Opacity for ghost mode (default: 0.15)
     * @param desaturate - Whether to desaturate color (default: true) - ignored if ghostColor is provided
     * @param ghostColor - Optional custom color for ghosted elements (e.g., {r: 1, g: 1, b: 1} for white)
     */
    setElementGhost(elements: {
        modelId: string;
        elementId: string;
    }[], ghostOpacity?: number, desaturate?: boolean, ghostColor?: {
        r: number;
        g: number;
        b: number;
    }): void;
    /**
     * Ghost all elements EXCEPT the specified ones
     * Focused elements remain fully opaque, everything else becomes ghosted
     *
     * @param focusElements - Elements to keep fully visible
     * @param ghostOpacity - Opacity for non-focused elements (default: 0.1)
     * @param ghostColor - Optional custom color for ghosted elements (e.g., {r: 1, g: 1, b: 1} for white)
     */
    ghostExcept(focusElements: {
        modelId: string;
        elementId: string;
    }[], ghostOpacity?: number, ghostColor?: {
        r: number;
        g: number;
        b: number;
    }): void;
    /**
     * Create a depth-only pre-pass mesh that writes depth for focused elements.
     * Shares the same geometry; uses alphaTest to discard ghost fragments.
     */
    private _createDepthPrePass;
    /**
     * Remove and dispose the depth pre-pass mesh
     */
    private _removeDepthPrePass;
    /**
     * Reset all element opacities to fully opaque and restore original colors
     */
    resetElementOpacity(): void;
    /**
     * Check if any element has semi-transparent opacity
     */
    hasTransparentElements(): boolean;
    /**
     * Check if MOST elements are transparent (for deciding depth write strategy)
     * Returns true if more than 50% of elements have transparency
     */
    private _isMostlyTransparent;
    /**
     * 🔧 Update material depth write based on transparency state
     * When MOST elements are semi-transparent, disable depth write to fix see-through issues
     * Also respects originally transparent materials (windows, glass)
     */
    private _updateDepthWriteForTransparency;
    /**
     * 🔧 INTERNAL: Update alpha values based on visibility state
     * This is the core method that applies hide/isolate states to the GPU buffer
     */
    private _updateAlphaVisibility;
    findElementByFaceIndex(faceIndex: number): {
        modelId: string;
        elementId: string;
    } | null;
    /**
     * Changes the color of multiple elements in the merged mesh.
     * Works with RGBA color buffer (preserves existing alpha values)
     * @param elements - An array of elements, each containing `modelId` and `elementId`.
     * @param color - The new RGB color to apply
     * @param isTemporary - Override for temporary, if element has temporary color it will turn back this color, otherwise will turn back to original
     */
    /**
     * Changes the color of multiple elements in the merged mesh.
     * Works with RGBA color buffer (preserves existing alpha values)
     * @param elements - An array of elements, each containing `modelId` and `elementId`.
     * @param color - The new RGB color to apply
     * @param isTemporary - If true, stores this color as a temporary layer that will be restored on reset
     *
     * @example
     * ```typescript
     * // Normal color change (resets to original)
     * mesh.changeColor([{ modelId: "0", elementId: "abc" }], { r: 1, g: 0, b: 0 });
     *
     * // Temporary color (resets to this color instead of original)
     * mesh.changeColor([{ modelId: "0", elementId: "abc" }], { r: 0, g: 1, b: 0 }, true);
     * // Later, any non-temporary color change will reset to green instead of original
     * ```
     */
    changeColor(elements: {
        modelId: string;
        elementId: string;
    }[], color: {
        r: number;
        g: number;
        b: number;
    }, isTemporary?: boolean): void;
    /**
     * Clears temporary colors for specified elements or all elements
     * @param elements - Elements to clear temporary colors for, or null to clear all
     */
    clearTemporaryColors(elements?: {
        modelId: string;
        elementId: string;
    }[] | null): void;
    /**
     * Reset color of an element back to the original color
     */
    /**
     * Resets the color of elements back to temporary color (if exists) or original color.
     * Works with RGBA color buffer (preserves existing alpha values)
     * @param elements - Array of elements to reset, or `null` to reset the entire mesh.
     * @param excepts - Elements that should receive a different color instead of original/temporary
     *
     * @example
     * ```typescript
     * // Reset all elements to temporary color (if set) or original color
     * mesh.resetColor(null);
     *
     * // Reset specific elements
     * mesh.resetColor([{ modelId: "0", elementId: "abc" }, { modelId: "0", elementId: "def" }]);
     *
     * // Reset all except some elements with custom colors
     * mesh.resetColor(null, [{ elements: [{ modelId: "0", elementId: "abc" }], color: { r: 1, g: 0, b: 0 } }]);
     * ```
     */
    resetColor(elements: {
        modelId: string;
        elementId: string;
    }[] | null, excepts?: {
        elements: {
            modelId: string;
            elementId: string;
        }[];
        color: {
            r: number;
            g: number;
            b: number;
        };
    }[]): void;
    assignUniqueFaceColors(): void;
    /**
     * Assigns a random color to each element in the merged geometry.
     */
    /**
     * Generates a completely random RGB color.
     */
    private generateRandomColor;
    /**
     * Generates a unique color based on an index.
     */
    private generateUniqueColor;
    /**
     * Converts HSL to RGB.
     */
    private hslToRgb;
    private _isGeneratedLights;
    private _pointLight;
    enableLights(): void;
    disableLights(): void;
    calculateCenter(buffer: Float32Array): Vector3 | null;
    getFarthestDistance(centerPoint: Vector3, placePoints: Vector3[]): number;
    getElementBoxs(elements: {
        modelId: string;
        elementId: string;
    }[]): Box3 | null;
    getTotalVertexCount(): number;
    getObjectCount(): number;
    /**
     * Create simplified LOD versions of this batched mesh
     * All LOD meshes maintain full element mapping functionality (hide, isolate, changeColor)
     *
     * @param lodLevels - Array of simplification options for each LOD level
     * @returns Promise resolving to array of meshes [original, LOD1, LOD2, ...]
     *
     * @example
     * ```typescript
     * const lodMeshes = await originalMesh.createSimplifiedLODs([
     *   { ratio: 0.7, error: 0.01 }, // LOD1: 70% detail
     *   { ratio: 0.4, error: 0.02 }, // LOD2: 40% detail
     *   { ratio: 0.2, error: 0.05 }, // LOD3: 20% detail
     * ]);
     *
     * // All LODs support full operations
     * lodMeshes.forEach(mesh => mesh.hide(elements)); // Works on all!
     * ```
     */
    createSimplifiedLODs(lodLevels: Array<{
        ratio?: number;
        error?: number;
        lockBorder?: boolean;
        optimizeMemory?: boolean;
    }>): Promise<ViralBatchedMesh[]>;
    /**
     * FAST: Create simplified LOD by simplifying entire geometry at once
     * ⚠️ This breaks element mapping - hide/isolate/changeColor won't work on simplified mesh
     * Use this when you only need visual LOD without element operations
     *
     * @param options - Simplification options
     * @returns Promise resolving to simplified mesh
     *
     * @example
     * ```typescript
     * const lodMesh = await originalMesh.createSimplifiedLODFast({ ratio: 0.5 });
     * // 10x-100x faster than createSimplifiedLODs but no element operations
     * ```
     */
    createSimplifiedLODFast(options: {
        ratio?: number;
        error?: number;
        lockBorder?: boolean;
        optimizeMemory?: boolean;
    }): Promise<ViralBatchedMesh>;
    /**
     * ! Disposes of the ViralBatchedMesh properly, when dispose we dont need to dispose material
     */
    dispose(): void;
}
