"""Test the primitive shapes."""

from __future__ import annotations

from typing import Any

import numpy as np
import pytest

import microgen
from microgen.shape import (
    Box,
    Capsule,
    Cylinder,
    Ellipsoid,
    ExtrudedPolygon,
    Polyhedron,
    Shape,
    ShapeError,
    Sphere,
)

# ruff: noqa: S101 assert https://docs.astral.sh/ruff/rules/assert/
# ruff: noqa: E501 line-too-long https://docs.astral.sh/ruff/rules/line-too-long/


@pytest.mark.parametrize(
    ("shape", "params"),
    [
        (Box, {"dim": (0.15, 0.31, 0.4)}),
        (Capsule, {"height": 0.5, "radius": 0.1}),
        (Cylinder, {"height": 0.5, "radius": 0.1}),
        (Ellipsoid, {"radii": (0.15, 0.31, 0.4)}),
        (
            ExtrudedPolygon,
            {"listCorners": [(0, 0), (0, 1), (1, 1), (1, 0)], "height": 0.3},
        ),
        (
            Polyhedron,
            {
                "dic": microgen.shape.polyhedron.read_obj(
                    "examples/BasicShapes/platon/tetrahedron.obj",
                ),
            },
        ),
        (Sphere, {"radius": 0.15}),
    ],
)
def test_new_geometry_and_native_shape_must_have_same_volume(
    shape: type[Shape],
    params: dict[str, Any],
) -> None:
    """Test if the newGeometry generates the same volume as the native shape."""
    key = shape.__name__
    new_geom = microgen.shape.new_geometry(shape=key, param_geom=params)
    native_shape = shape(**params)

    assert new_geom.generate_vtk().volume == native_shape.generate_vtk().volume


def test_new_geometry_given_wrong_shape_must_raise_error() -> None:
    """Test if the newGeometry raises an error when the shape is not recognized."""
    fake_shape = "fake"
    expected_err_msg = f"{fake_shape} name not implemented"
    with pytest.raises(ShapeError, match=expected_err_msg):
        microgen.shape.new_geometry(shape=fake_shape, param_geom={"fake": 0})


@pytest.mark.parametrize(
    "shape",
    [Box, Capsule, Cylinder, Ellipsoid, ExtrudedPolygon, Polyhedron, Sphere],
)
def test_shape_cad_and_vtk_volume_must_correspond(shape: type[Shape]) -> None:
    """Test that the volume of the shape generated by the CAD and VTK methods correspond."""
    geom = shape()
    shape_cad = geom.generate()
    shape_vtk = geom.generate_vtk()

    volume_cad = shape_cad.Volume()

    assert volume_cad > 0
    assert np.isclose(volume_cad, shape_vtk.volume, rtol=1e-2)
