from pathlib import Path

import numpy as np
import trimesh

from flexiforge.geometry import (
    analyse_mesh,
    choose_cut_normal,
    export_forge_package,
    rank_joint_candidates,
    repair_mesh,
)


def test_analysis_and_candidate_ranking():
    mesh = trimesh.creation.box(extents=[60, 30, 12])
    mesh, notes = repair_mesh(mesh)
    analysis = analyse_mesh(mesh, notes)
    assert analysis.watertight
    assert analysis.faces == 12
    candidates = rank_joint_candidates(mesh, np.zeros(3), "wiggle", 0.35)
    assert candidates[0]["type"] in {"hinge", "flexi"}
    assert candidates[0]["score"] >= candidates[-1]["score"]


def test_cut_normal_is_unit_and_flat_for_flat_model():
    mesh = trimesh.creation.box(extents=[80, 20, 8])
    normal = choose_cut_normal(mesh, np.array([25.0, 2.0, 0.0]))
    assert np.isclose(np.linalg.norm(normal), 1.0)
    assert abs(normal[2]) < 1e-6


def test_all_joint_exports(tmp_path: Path):
    mesh = trimesh.creation.box(extents=[60, 30, 16])
    for joint_type in ("hinge", "flexi", "ball_socket"):
        result = export_forge_package(
            tmp_path,
            f"test_{joint_type}",
            mesh,
            np.zeros(3),
            np.array([1.0, 0.0, 0.0]),
            joint_type,
            0.35,
            8.0,
        )
        package = result["directory"]
        assert (package / result["files"]["part_a"]).exists()
        assert (package / result["files"]["part_b"]).exists()
        assert (package / result["files"]["assembled"]).exists()
        assert (package / result["files"]["print_layout"]).exists()
