use cord_decompile::crawler::oracle::SdfOracle;
use cord_decompile::crawler::scheduler::CrawlerScheduler;
use cord_decompile::crawler::CrawlerConfig;
use cord_decompile::mesh::{Vec3, AABB};

/// A perfect sphere oracle for testing (no mesh needed).
struct SphereOracle {
    center: Vec3,
    radius: f64,
}

impl SdfOracle for SphereOracle {
    fn sdf(&self, p: Vec3) -> f64 {
        (p - self.center).length() - self.radius
    }
}

#[test]
fn crawlers_find_sphere_surface() {
    let oracle = SphereOracle {
        center: Vec3::zero(),
        radius: 1.0,
    };

    let bounds = AABB {
        min: Vec3::new(-2.0, -2.0, -2.0),
        max: Vec3::new(2.0, 2.0, 2.0),
    };

    let config = CrawlerConfig {
        initial_probes: 32,
        crawlers_per_contact: 2,
        step_fraction: 0.01,
        surface_epsilon: 1e-3,
        max_steps: 2000,
        ..Default::default()
    };

    let mut scheduler = CrawlerScheduler::new(bounds, config);
    let samples = scheduler.run(&oracle);

    assert!(!samples.is_empty(), "should find surface samples");

    // All samples should be on or very near the sphere surface
    for s in &samples {
        let dist = s.position.length();
        assert!(
            (dist - 1.0).abs() < 0.05,
            "sample at distance {dist} from origin, expected ~1.0"
        );
    }
}
