use crate::bvh::BVH;
use crate::mesh::{AABB, TriangleMesh, Vec3};
use crate::sparse_grid::{CellKey, SparseGrid};
use std::collections::HashMap;

/// Per-cell density analysis comparing mesh triangle density to uniform.
pub struct DensityMap {
    pub cells: HashMap<CellKey, DensityInfo>,
    pub mean_density: f64,
    pub max_density: f64,
}

#[derive(Debug, Clone, Copy)]
pub struct DensityInfo {
    /// Triangles per unit volume in this cell.
    pub triangle_density: f64,
    /// Ratio to the mean density. >1 = more complex geometry (curves, fillets).
    pub relative_density: f64,
    /// Classification of this region's geometric character.
    pub surface_type: SurfaceType,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SurfaceType {
    /// Low density: likely a flat surface.
    Flat,
    /// Medium density: gentle curve or chamfer.
    Curved,
    /// High density: tight radius, fillet, or complex feature.
    HighDetail,
    /// Interior or exterior — no surface here.
    Empty,
}

pub fn analyze(mesh: &TriangleMesh, grid: &SparseGrid) -> DensityMap {
    let bvh = BVH::build(mesh);

    let mut cell_densities: HashMap<CellKey, DensityInfo> = HashMap::new();
    let mut total_density = 0.0;
    let mut count = 0usize;
    let mut max_density = 0.0f64;

    let leaves = grid.leaf_cells();

    for (key, data) in &leaves {
        if !data.is_surface {
            cell_densities.insert(**key, DensityInfo {
                triangle_density: 0.0,
                relative_density: 0.0,
                surface_type: SurfaceType::Empty,
            });
            continue;
        }

        let cell_bounds = cell_aabb(grid, key);
        let volume = cell_volume(&cell_bounds);
        if volume < 1e-15 {
            continue;
        }

        let tri_count = bvh.count_in_region(mesh, &cell_bounds);
        let density = tri_count as f64 / volume;

        total_density += density;
        count += 1;
        max_density = max_density.max(density);

        cell_densities.insert(**key, DensityInfo {
            triangle_density: density,
            relative_density: 0.0, // filled in second pass
            surface_type: SurfaceType::Flat, // placeholder
        });
    }

    let mean_density = if count > 0 { total_density / count as f64 } else { 1.0 };

    // Second pass: compute relative density and classify
    for info in cell_densities.values_mut() {
        if info.triangle_density == 0.0 {
            continue;
        }
        info.relative_density = info.triangle_density / mean_density;

        info.surface_type = if info.relative_density < 0.5 {
            SurfaceType::Flat
        } else if info.relative_density < 2.0 {
            SurfaceType::Curved
        } else {
            SurfaceType::HighDetail
        };
    }

    DensityMap {
        cells: cell_densities,
        mean_density,
        max_density,
    }
}

fn cell_aabb(grid: &SparseGrid, key: &CellKey) -> AABB {
    let divisions = (1u32 << key.depth) as f64;
    let extent = grid.bounds.max - grid.bounds.min;
    let cell_size = Vec3::new(
        extent.x / divisions,
        extent.y / divisions,
        extent.z / divisions,
    );
    let min = Vec3::new(
        grid.bounds.min.x + key.x as f64 * cell_size.x,
        grid.bounds.min.y + key.y as f64 * cell_size.y,
        grid.bounds.min.z + key.z as f64 * cell_size.z,
    );
    AABB { min, max: min + cell_size }
}

fn cell_volume(aabb: &AABB) -> f64 {
    let e = aabb.max - aabb.min;
    e.x * e.y * e.z
}
