//! Mesh decompiler — STL/OBJ → SDF tree.
//!
//! Pipeline: mesh → BVH → sparse octree → density analysis → RANSAC
//! primitive detection → Riesz/monogenic CSG boolean classification →
//! reconstructed SDF tree.
//!
//! Also includes a crawler-based surface exploration mode for adaptive
//! sampling without a fixed grid.

pub mod mesh;
pub mod bvh;
pub mod sparse_grid;
pub mod density;
pub mod fit;
pub mod reconstruct;
pub mod monogenic_classify;
pub mod crawler;

use anyhow::Result;
use cord_sdf::SdfNode;
use mesh::TriangleMesh;

/// Full decompilation pipeline: foreign mesh → SDF tree.
///
/// Primitive detection via iterative RANSAC, then Riesz/monogenic
/// classification of each primitive as additive or subtractive.
pub fn decompile(mesh: &TriangleMesh, config: &DecompileConfig) -> Result<DecompileResult> {
    let bvh = bvh::BVH::build(mesh);
    let grid = sparse_grid::SparseGrid::from_mesh(mesh, &bvh, config.grid_depth);
    let density_map = density::analyze(mesh, &grid);
    let samples = grid.surface_samples();
    let primitives = fit::detect_primitives(&grid, &density_map, config);

    let subtractive = monogenic_classify::classify_subtractive(
        mesh,
        &bvh,
        &grid.bounds,
        &primitives,
        &samples,
        config.monogenic_resolution,
    );
    let sdf = reconstruct::build_sdf_tree(&primitives, &samples, &subtractive);

    Ok(DecompileResult {
        grid,
        density_map,
        primitives,
        sdf,
    })
}

pub struct DecompileConfig {
    pub grid_depth: u8,
    pub ransac_iterations: u32,
    pub distance_threshold: f64,
    pub normal_threshold: f64,
    pub min_support_ratio: f64,
    /// Resolution of the regular grid for monogenic signal computation.
    /// Higher values improve classification accuracy at the cost of
    /// O(n³ log n) FFT time. 32-64 is typical.
    pub monogenic_resolution: usize,
}

impl Default for DecompileConfig {
    fn default() -> Self {
        Self {
            grid_depth: 7,
            ransac_iterations: 1000,
            distance_threshold: 0.01,
            normal_threshold: 0.95,
            min_support_ratio: 0.05,
            monogenic_resolution: 32,
        }
    }
}

pub struct DecompileResult {
    pub grid: sparse_grid::SparseGrid,
    pub density_map: density::DensityMap,
    pub primitives: Vec<fit::DetectedPrimitive>,
    pub sdf: SdfNode,
}

/// Crawler-based decompilation: agent-based surface exploration.
/// Faster and more adaptive than grid-based approach.
pub fn decompile_crawl(
    mesh: &TriangleMesh,
    config: &crawler::CrawlerConfig,
) -> Result<CrawlResult> {
    let bvh = bvh::BVH::build(mesh);
    let samples = crawler::cpu::run_cpu(mesh, &bvh, config.clone());

    // Count distinct faces
    let mut face_ids: std::collections::HashSet<u32> = std::collections::HashSet::new();
    for s in &samples {
        face_ids.insert(s.face_id);
    }

    Ok(CrawlResult {
        samples,
        face_count: face_ids.len(),
    })
}

pub struct CrawlResult {
    pub samples: Vec<crawler::SurfaceHit>,
    pub face_count: usize,
}

/// High-level API: load a mesh file and run the full decomposition pipeline.
///
/// Returns both the SdfNode tree and the intermediate DecompileResult
/// for callers that need primitive-level detail.
pub fn reconstruct_mesh(
    path: &std::path::Path,
    config: &DecompileConfig,
) -> Result<DecompileResult> {
    let mesh = mesh::TriangleMesh::load(path)?;
    decompile(&mesh, config)
}
