from inire.geometry.collision import CollisionEngine
from inire.geometry.components import Bend90
from inire.geometry.primitives import Port
from inire.router.astar import AStarRouter
from inire.router.cost import CostEvaluator
from inire.router.danger_map import DangerMap
from inire.router.pathfinder import PathFinder


def test_arc_resolution_sagitta() -> None:
    start = Port(0, 0, 0)
    # R=10, 90 deg bend.
    # High tolerance (0.5um) -> few segments
    res_coarse = Bend90.generate(start, radius=10.0, width=2.0, direction="CCW", sagitta=0.5)
    # Low tolerance (1nm) -> many segments
    res_fine = Bend90.generate(start, radius=10.0, width=2.0, direction="CCW", sagitta=0.001)


    # Check number of points in the polygon exterior
    # (num_segments + 1) * 2 points usually
    pts_coarse = len(res_coarse.geometry[0].exterior.coords)
    pts_fine = len(res_fine.geometry[0].exterior.coords)

    assert pts_fine > pts_coarse


def test_locked_paths() -> None:
    engine = CollisionEngine(clearance=2.0)
    danger_map = DangerMap(bounds=(0, -50, 100, 50))
    danger_map.precompute([])
    evaluator = CostEvaluator(engine, danger_map)
    router = AStarRouter(evaluator, bend_radii=[5.0, 10.0], sbend_radii=[5.0, 10.0])
    pf = PathFinder(router, evaluator)

    # 1. Route Net A
    netlist_a = {"netA": (Port(0, 0, 0), Port(50, 0, 0))}
    results_a = pf.route_all(netlist_a, {"netA": 2.0})
    assert results_a["netA"].is_valid

    # 2. Lock Net A
    engine.lock_net("netA")

    # 3. Route Net B through the same space. It should detour or fail.
    # We'll place Net B's start/target such that it MUST cross Net A's physical path.
    netlist_b = {"netB": (Port(0, -5, 0), Port(50, 5, 0))}

    # Route Net B
    results_b = pf.route_all(netlist_b, {"netB": 2.0})

    # Net B should be is_valid (it detoured) or at least not have collisions
    # with Net A in the dynamic set (because netA is now static).
    # Since netA is static, netB will see it as a HARD collision if it tries to cross.

    # Our A* will find a detour around the static obstacle.
    assert results_b["netB"].is_valid

    # Verify geometry doesn't intersect locked netA (physical check)
    poly_a = [p.geometry[0] for p in results_a["netA"].path]
    poly_b = [p.geometry[0] for p in results_b["netB"].path]

    for pa in poly_a:
        for pb in poly_b:
            assert not pa.intersects(pb)
