from shapely.geometry import Polygon

from inire.geometry.collision import CollisionEngine
from inire.geometry.primitives import Port


def test_collision_detection() -> None:
    # Clearance = 2um
    engine = CollisionEngine(clearance=2.0)

    # 10x10 um obstacle at (10,10)
    obstacle = Polygon([(10, 10), (20, 10), (20, 20), (10, 20)])
    engine.add_static_obstacle(obstacle)

    # 1. Direct hit
    test_poly = Polygon([(12, 12), (13, 12), (13, 13), (12, 13)])
    assert engine.is_collision(test_poly, net_width=2.0)

    # 2. Far away
    test_poly_far = Polygon([(0, 0), (5, 0), (5, 5), (0, 5)])
    assert not engine.is_collision(test_poly_far, net_width=2.0)

    # 3. Near hit (within clearance)
    # Obstacle edge at x=10.
    # test_poly edge at x=9.
    # Distance = 1.0 um.
    # Required distance (Wi+C)/2 = 2.0. Collision!
    test_poly_near = Polygon([(8, 10), (9, 10), (9, 15), (8, 15)])
    assert engine.is_collision(test_poly_near, net_width=2.0)


def test_safety_zone() -> None:
    # Use zero clearance for this test to verify the 2nm port safety zone
    # against the physical obstacle boundary.
    engine = CollisionEngine(clearance=0.0)

    obstacle = Polygon([(10, 10), (20, 10), (20, 20), (10, 20)])
    engine.add_static_obstacle(obstacle)

    # Port exactly on the boundary
    start_port = Port(10.0, 12.0, 0)

    # Move starting from this port that overlaps the obstacle by 1nm
    # (Inside the 2nm safety zone)
    test_poly = Polygon([(9.999, 11.9995), (10.001, 11.9995), (10.001, 12.0005), (9.999, 12.0005)])

    assert not engine.is_collision(test_poly, net_width=0.001, start_port=start_port)


def test_configurable_max_net_width() -> None:
    # Large max_net_width (10.0) -> large pre-dilation (6.0)
    engine = CollisionEngine(clearance=2.0, max_net_width=10.0)

    obstacle = Polygon([(20, 20), (25, 20), (25, 25), (20, 25)])
    engine.add_static_obstacle(obstacle)

    test_poly = Polygon([(15, 20), (16, 20), (16, 25), (15, 25)])
    # physical check: dilated test_poly by C/2 = 1.0.
    # Dilated test_poly bounds: (14, 19, 17, 26).
    # obstacle: (20, 20, 25, 25). No physical collision.
    assert not engine.is_collision(test_poly, net_width=2.0)
