use bone_kernel::{BrepError, BrepSolid};
use bone_types::{CancelFlag, FeatureId, StepEntityKind};
use slotmap::SlotMap;
use truck_modeling::{Point3, Rad, Solid, Vector3, builder};
use truck_stepio::out::StepModels;

fn envelope(body: &str) -> String {
    format!(
        "ISO-10303-21;\nHEADER;\nFILE_DESCRIPTION((''),'2;1');\nFILE_NAME('','1970-01-01T00:00:00',(''),(''),'','','');\nFILE_SCHEMA(('AUTOMOTIVE_DESIGN {{ 1 0 10303 214 1 1 1 1 }}'));\nENDSEC;\nDATA;\n{body}ENDSEC;\nEND-ISO-10303-21;\n"
    )
}

fn feature() -> FeatureId {
    let mut features: SlotMap<FeatureId, ()> = SlotMap::with_key();
    features.insert(())
}

#[test]
fn analytic_revolved_surface_is_typed_unsupported() {
    let v0 = builder::vertex(Point3::new(2.0, 0.0, 0.0));
    let v1 = builder::vertex(Point3::new(3.0, 0.0, 0.0));
    let edge = builder::line(&v0, &v1);
    let face = builder::tsweep(&edge, Vector3::new(0.0, 0.0, 1.0));
    let revolved: Solid = builder::rsweep(
        &face,
        Point3::new(0.0, 0.0, 0.0),
        Vector3::unit_z(),
        Rad(2.0 * std::f64::consts::PI),
    );
    let doc = envelope(&StepModels::from_iter([&revolved.compress()]).to_string());
    assert!(matches!(
        BrepSolid::from_step(&doc, feature(), None, CancelFlag::never()),
        Err(BrepError::StepUnsupported {
            kind: StepEntityKind::SweptSurface
        })
    ));
}

#[test]
fn text_without_a_data_section_reports_no_data() {
    let doc = "ISO-10303-21;\nHEADER;\nENDSEC;\nEND-ISO-10303-21;\n";
    assert!(matches!(
        BrepSolid::from_step(doc, feature(), None, CancelFlag::never()),
        Err(BrepError::StepNoData)
    ));
}

#[test]
fn preset_cancel_flag_aborts_the_parse() {
    let doc = "ISO-10303-21;\nHEADER;\nENDSEC;\nEND-ISO-10303-21;\n";
    let flag = std::sync::atomic::AtomicBool::new(true);
    assert!(matches!(
        BrepSolid::from_step(doc, feature(), None, CancelFlag::new(&flag)),
        Err(BrepError::Canceled)
    ));
}

#[test]
fn unparseable_data_section_reports_syntax() {
    let doc = "ISO-10303-21;\nDATA;\nthis is not a record\nENDSEC;\n";
    assert!(matches!(
        BrepSolid::from_step(doc, feature(), None, CancelFlag::never()),
        Err(BrepError::StepSyntax)
    ));
}

#[test]
fn multiple_bodies_are_rejected_not_merged() {
    let truck_cube = |origin_x: f64| {
        let corner = builder::vertex(Point3::new(origin_x, 0.0, 0.0));
        let edge = builder::tsweep(&corner, Vector3::new(1.0, 0.0, 0.0));
        let face = builder::tsweep(&edge, Vector3::new(0.0, 1.0, 0.0));
        let solid: Solid = builder::tsweep(&face, Vector3::new(0.0, 0.0, 1.0));
        solid.compress()
    };
    let first = truck_cube(0.0);
    let second = truck_cube(5.0);
    let doc = envelope(&StepModels::from_iter([&first, &second]).to_string());
    assert!(matches!(
        BrepSolid::from_step(&doc, feature(), None, CancelFlag::never()),
        Err(BrepError::StepMultipleSolids { count: 2 })
    ));
}
