from __future__ import annotations

"""Geographic presets and tagging rules for OpenStreetMap imports."""

from dataclasses import dataclass
from typing import Iterable, Mapping, Tuple


@dataclass(frozen=True)
class BoundingBox:
    """Geographic bounding box expressed as WGS84 coordinates."""

    name: str
    north: float
    south: float
    east: float
    west: float
    description: str | None = None

    def __post_init__(self) -> None:
        if self.north <= self.south:
            msg = f"north ({self.north}) must be greater than south ({self.south})"
            raise ValueError(msg)
        if self.east <= self.west:
            msg = f"east ({self.east}) must be greater than west ({self.west})"
            raise ValueError(msg)

    def contains(self, latitude: float, longitude: float) -> bool:
        """Return True when the given coordinate lies inside the bounding box."""

        return (
            self.south <= latitude <= self.north and self.west <= longitude <= self.east
        )

    def to_overpass_arg(self) -> str:
        """Return the bbox string used for Overpass API queries."""

        return f"{self.south},{self.west},{self.north},{self.east}"


# Primary metropolitan areas we plan to support.
DEFAULT_REGIONS: Tuple[BoundingBox, ...] = (
    BoundingBox(
        name="berlin_metropolitan",
        north=52.6755,
        south=52.3381,
        east=13.7611,
        west=13.0884,
        description="Berlin and surrounding rapid transit network",
    ),
    BoundingBox(
        name="hamburg_metropolitan",
        north=53.7447,
        south=53.3950,
        east=10.3253,
        west=9.7270,
        description="Hamburg S-Bahn and harbor region",
    ),
    BoundingBox(
        name="munich_metropolitan",
        north=48.2485,
        south=47.9960,
        east=11.7229,
        west=11.3600,
        description="Munich S-Bahn core and airport corridor",
    ),
)


# Tags that identify passenger stations and stops.
STATION_TAG_FILTERS: Mapping[str, Tuple[str, ...]] = {
    "railway": ("station", "halt", "stop"),
    "public_transport": ("station", "stop_position", "platform"),
    "train": ("yes", "regional", "suburban"),
}


# Tags that describe rail infrastructure usable for train routing.
TRACK_ALLOWED_RAILWAY_TYPES: Tuple[str, ...] = (
    "rail",
    "light_rail",
    "subway",
    "tram",
    "narrow_gauge",
    "disused",
    "construction",
)


TRACK_TAG_FILTERS: Mapping[str, Tuple[str, ...]] = {
    "railway": TRACK_ALLOWED_RAILWAY_TYPES,
}


# Track ingestion policy
TRACK_EXCLUDED_SERVICE_TAGS: Tuple[str, ...] = (
    "yard",
    "siding",
    "spur",
    "crossover",
    "industrial",
    "military",
)

TRACK_EXCLUDED_USAGE_TAGS: Tuple[str, ...] = (
    "military",
    "tourism",
)

TRACK_MIN_LENGTH_METERS: float = 75.0

TRACK_STATION_SNAP_RADIUS_METERS: float = 350.0


def compile_overpass_filters(filters: Mapping[str, Iterable[str]]) -> str:
    """Build an Overpass boolean expression that matches the provided filters."""

    parts: list[str] = []
    for key, values in filters.items():
        options = "|".join(sorted(set(values)))
        parts.append(f'  ["{key}"~"^({options})$"]')
    return "\n".join(parts)


__all__ = [
    "BoundingBox",
    "DEFAULT_REGIONS",
    "STATION_TAG_FILTERS",
    "TRACK_ALLOWED_RAILWAY_TYPES",
    "TRACK_TAG_FILTERS",
    "TRACK_EXCLUDED_SERVICE_TAGS",
    "TRACK_EXCLUDED_USAGE_TAGS",
    "TRACK_MIN_LENGTH_METERS",
    "TRACK_STATION_SNAP_RADIUS_METERS",
    "compile_overpass_filters",
]
