from abc import ABC, abstractmethod
from decimal import Decimal


class BoundaryIntersectionBackend(ABC):
    @abstractmethod
    def intersect_route_with_boundaries(self, route_coords: list[tuple[float, float]], boundaries: list) -> list[dict]:
        """
        route_coords: [(lng, lat), ...] in route order.
        boundaries: list of CountryBoundary instances.
        Returns: [{"country_code": str, "km": Decimal}, ...] for segments with km > 0.
        """
        ...


class ShapelyBackend(BoundaryIntersectionBackend):
    def intersect_route_with_boundaries(self, route_coords, boundaries):
        from shapely.geometry import LineString, shape
        from shapely.ops import transform
        import pyproj

        if len(route_coords) < 2:
            return []

        project = pyproj.Transformer.from_crs(
            'EPSG:4326', 'EPSG:3857', always_xy=True,
        ).transform

        route = LineString(route_coords)
        results = []

        for boundary in boundaries:
            poly = shape(boundary.geojson)
            if not route.intersects(poly):
                continue

            intersection = route.intersection(poly)
            if intersection.is_empty:
                continue

            intersection_m = transform(project, intersection)
            length_km = Decimal(str(intersection_m.length / 1000))

            if length_km <= 0:
                continue

            results.append({'country_code': boundary.country_code, 'km': length_km})

        return results
