from typing import List, Optional

from geojson_pydantic import FeatureCollection

from traveltimepy.accept_type import AcceptType
from traveltimepy.requests.common import (
    Location,
    Rectangle,
    CellProperty,
    Coordinates,
)
from traveltimepy.requests.distance_map import (
    DistanceMapDepartureSearch,
    DistanceMapArrivalSearch,
    DistanceMapUnion,
    DistanceMapIntersection,
    DistanceMapRequest,
)
from traveltimepy.requests.geocoding import (
    GeocodingRequest,
    ReverseGeocodingRequest,
)
from traveltimepy.requests.geohash import (
    GeoHashDepartureSearch,
    GeoHashArrivalSearch,
    GeoHashUnion,
    GeoHashIntersection,
    GeoHashRequest,
)
from traveltimepy.requests.geohash_fast import (
    GeoHashFastArrivalSearches,
    GeoHashFastRequest,
    GeoHashFastUnion,
    GeoHashFastIntersection,
)
from traveltimepy.requests.h3 import (
    H3DepartureSearch,
    H3ArrivalSearch,
    H3Union,
    H3Intersection,
    H3Request,
)
from traveltimepy.requests.h3_fast import (
    H3FastRequest,
    H3FastArrivalSearches,
    H3FastUnion,
    H3FastIntersection,
)
from traveltimepy.requests.postcodes import (
    PostcodesRequest,
    PostcodeArrivalSearch,
    PostcodeDepartureSearch,
)
from traveltimepy.requests.postcodes_zones import (
    PostcodesDistrictsRequest,
    PostcodeFilterArrivalSearch,
    PostcodeFilterDepartureSearch,
    PostcodesSectorsRequest,
)
from traveltimepy.requests.routes import (
    RoutesArrivalSearch,
    RoutesDepartureSearch,
    RoutesRequest,
)
from traveltimepy.requests.supported_locations import SupportedLocationsRequest
from traveltimepy.requests.time_filter import (
    TimeFilterRequest,
    TimeFilterDepartureSearch,
    TimeFilterArrivalSearch,
)
from traveltimepy.requests.time_filter_fast import (
    TimeFilterFastArrivalSearches,
    TimeFilterFastRequest,
)
from traveltimepy.requests.time_filter_proto import (
    TimeFilterFastProtoRequest,
    TimeFilterFastProtoTransportation,
    RequestType,
    ProtoCountry,
)
from traveltimepy.requests.time_map import (
    TimeMapDepartureSearch,
    TimeMapArrivalSearch,
    TimeMapUnion,
    TimeMapIntersection,
    TimeMapRequest,
)
from traveltimepy.requests.time_map_fast import (
    TimeMapFastArrivalSearches,
    TimeMapFastRequest,
)
from traveltimepy.requests.time_map_fast_geojson import TimeMapFastGeojsonRequest
from traveltimepy.requests.time_map_fast_wkt import TimeMapFastWKTRequest
from traveltimepy.requests.time_map_geojson import TimeMapGeojsonRequest
from traveltimepy.requests.time_map_wkt import TimeMapWktRequest
from traveltimepy.responses.geohash import GeoHashResponse
from traveltimepy.responses.h3 import H3Response
from traveltimepy.responses.map_info import MapInfoResponse, Map
from traveltimepy.responses.postcodes import PostcodesResponse
from traveltimepy.responses.routes import RoutesResponse
from traveltimepy.responses.supported_locations import SupportedLocationsResponse
from traveltimepy.responses.time_filter import TimeFilterResponse
from traveltimepy.responses.time_filter_fast import (
    TimeFilterFastResponse,
)
from traveltimepy.responses.time_filter_proto import TimeFilterProtoResponse
from traveltimepy.responses.time_map import TimeMapResponse
from traveltimepy.responses.time_map_wkt import TimeMapWKTResponse
from traveltimepy.responses.zones import (
    PostcodesDistrictsResponse,
    PostcodesSectorsResponse,
)
from traveltimepy.sync_base_client import SyncBaseClient


class Client(SyncBaseClient):

    def time_filter(
        self,
        locations: List[Location],
        departure_searches: List[TimeFilterDepartureSearch],
        arrival_searches: List[TimeFilterArrivalSearch],
    ) -> TimeFilterResponse:
        """Calculate comprehensive distance matrix with full configurability.

        Full-featured endpoint supporting specific departure/arrival times, all transport
        modes, range searches, and detailed routing information. Provides maximum
        flexibility for complex travel time analysis.

        Args:
            locations: List of all locations referenced by ID in searches
            departure_searches: Departure-based searches with specific departure times.
                               Max 10 searches.
            arrival_searches: Arrival-based searches with specific arrival times.
                             Max 10 searches.

        Returns:
            TimeFilterResponse: Comprehensive travel time data including times, distances,
                               routes, and fares based on requested properties.
        """
        return self._api_call_post(
            TimeFilterResponse,
            "time-filter",
            AcceptType.JSON,
            TimeFilterRequest(
                locations=locations,
                departure_searches=departure_searches,
                arrival_searches=arrival_searches,
            ),
        )

    def time_filter_fast(
        self, locations: List[Location], arrival_searches: TimeFilterFastArrivalSearches
    ) -> TimeFilterFastResponse:
        """Calculate high-performance distance matrix with up to 100,000 destinations.

        Optimized endpoint for large-scale travel time calculations with extremely
        low response times. Trades configurability for performance and scale.

        Args:
            locations: List of all locations referenced by ID in searches
            arrival_searches: High-performance search configurations with one_to_many
                             and many_to_one patterns. Max 10 searches total.

        Returns:
            TimeFilterFastResponse: Travel times and distances for reachable locations
                                   based on requested properties.
        """

        return self._api_call_post(
            TimeFilterFastResponse,
            "time-filter/fast",
            AcceptType.JSON,
            TimeFilterFastRequest(
                locations=locations, arrival_searches=arrival_searches
            ),
        )

    def time_filter_fast_proto(
        self,
        origin_coordinate: Coordinates,
        destination_coordinates: List[Coordinates],
        transportation: TimeFilterFastProtoTransportation,
        travel_time: int,
        request_type: RequestType,
        country: ProtoCountry,
        with_distance: bool,
    ) -> TimeFilterProtoResponse:
        """Calculate ultra-high-performance distance matrix using Protocol Buffers.

        Maximum performance endpoint using protobuf format for extremely large datasets.
        Optimized for scenarios requiring millions of travel time calculations with
        minimal latency and bandwidth usage.

        Args:
            origin_coordinate: Single origin coordinate (lat/lng)
            destination_coordinates: List of destination coordinates
            transportation: Transportation mode
            travel_time: Maximum journey time in seconds
            request_type: Type of request calculation
            country: Specific country for the calculation
            with_distance: Whether to include distance data in response

        Returns:
            TimeFilterProtoResponse: Response with travel times and optionally distances for reachable destinations.
        """
        return self._api_call_proto(
            TimeFilterFastProtoRequest(
                origin_coordinate,
                destination_coordinates,
                transportation,
                travel_time,
                request_type,
                country,
                with_distance,
            )
        )

    def map_info(self) -> List[Map]:
        res: MapInfoResponse = self._api_call_get(
            MapInfoResponse, "map-info", AcceptType.JSON, None
        )
        return res.maps

    def geocoding(
        self,
        query: str,
        limit: Optional[int] = None,
        within_countries: Optional[List[str]] = None,
        format_name: Optional[bool] = None,
        format_exclude_country: Optional[bool] = None,
        bounds: Optional[Rectangle] = None,
    ) -> FeatureCollection:
        """Match a query string to geographic coordinates using geocoding search.

        Converts addresses, postcodes, or venue names into geographic coordinates
        and location information. Supports filtering by country, bounding box.

        Args:
            query: A query to geocode. Can be an address, postcode, or venue name.
                   Examples: "SW1A 0AA", "Victoria street, London"
                   Including country/city improves accuracy.

            limit: Maximum number of results to return.
                   Must be between 1 and 50.

            within_countries: List of ISO 3166-1 alpha-2 or alpha-3 country codes
                             to limit results. Example: ["GB", "US"] or ["GBR", "USA"]

            format_name: If True, formats the name field to a well-formatted,
                        human-readable address. Experimental feature.

            format_exclude_country: If True, excludes country from the formatted name field.
                                   Only used when format_name is True.

            bounds: Geographic bounding box to limit search results.
                   Results will only include locations within this rectangle.

        Returns:
            FeatureCollection containing geocoding results with coordinates,
            addresses, confidence scores, and location metadata.
        """

        return self._api_call_get(
            FeatureCollection,
            "geocoding/search",
            AcceptType.JSON,
            GeocodingRequest(
                query=query,
                limit=limit,
                within_countries=within_countries,
                format_name=format_name,
                format_exclude_country=format_exclude_country,
                bounds=bounds,
            ).get_params(),
        )

    def reverse_geocoding(
        self,
        lat: float,
        lng: float,
    ) -> FeatureCollection:
        """Convert geographic coordinates to an address using reverse geocoding.

        Takes latitude and longitude coordinates and attempts to match them
        to the nearest address or location information.

        Args:
            lat: Latitude coordinate in decimal degrees.
                 Valid range: -90.0 to +90.0

            lng: Longitude coordinate in decimal degrees.
                 Valid range: -180.0 to +180.0

        Returns:
            FeatureCollection containing address information, confidence scores,
            and location metadata for the specified coordinates.

        Raises:
            400 Bad Request: If coordinates are far from land (e.g., in ocean).
                            Reverse search is only supported for points on land.
        """

        return self._api_call_get(
            FeatureCollection,
            "geocoding/reverse",
            AcceptType.JSON,
            ReverseGeocodingRequest(lat=lat, lng=lng).get_params(),
        )

    def supported_locations(
        self,
        locations: List[Location],
    ) -> SupportedLocationsResponse:
        return self._api_call_post(
            SupportedLocationsResponse,
            "supported-locations",
            AcceptType.JSON,
            SupportedLocationsRequest(locations=locations),
        )

    def time_map(
        self,
        arrival_searches: List[TimeMapArrivalSearch],
        departure_searches: List[TimeMapDepartureSearch],
        unions: List[TimeMapUnion],
        intersections: List[TimeMapIntersection],
    ) -> TimeMapResponse:
        """Creates travel time catchment area polygons with specific departure/arrival
        times, transport modes, and support for complex polygon operations.

        Args:
            arrival_searches: Arrival-based isochrone searches with specific arrival times.
                             Max 10 searches.
            departure_searches: Departure-based isochrone searches with specific departure times.
                               Max 10 searches.
            unions: Union operations combining multiple isochrone results
            intersections: Intersection operations finding overlapping areas

        Returns:
            TimeMapResponse: Comprehensive polygon data in JSON format including
                            individual isochrones, unions, and intersections.
        """
        return self._api_call_post(
            TimeMapResponse,
            "time-map",
            AcceptType.JSON,
            TimeMapRequest(
                arrival_searches=arrival_searches,
                departure_searches=departure_searches,
                unions=unions,
                intersections=intersections,
            ),
        )

    def time_map_geojson(
        self,
        arrival_searches: List[TimeMapArrivalSearch],
        departure_searches: List[TimeMapDepartureSearch],
    ) -> FeatureCollection:
        """Generate comprehensive travel time isochrones in GeoJSON format.

        Creates travel time catchment area polygons in GeoJSON format with full
        configurability, optimized for mapping libraries and web applications.

        Args:
            arrival_searches: Arrival-based isochrone searches with specific arrival times.
                             Max 10 searches.
            departure_searches: Departure-based isochrone searches with specific departure times.
                               Max 10 searches.

        Returns:
            FeatureCollection: GeoJSON FeatureCollection with detailed polygon geometries
                              ready for mapping library integration.
        """
        return self._api_call_post(
            FeatureCollection,
            "time-map",
            AcceptType.GEO_JSON,
            TimeMapGeojsonRequest(
                arrival_searches=arrival_searches, departure_searches=departure_searches
            ),
        )

    def time_map_wkt(
        self,
        arrival_searches: List[TimeMapArrivalSearch],
        departure_searches: List[TimeMapDepartureSearch],
    ) -> TimeMapWKTResponse:
        """Generate comprehensive travel time isochrones in WKT format.

        Creates travel time catchment area polygons in Well-Known Text format with
        full configurability, suitable for GIS applications and spatial databases.

        Args:
            arrival_searches: Arrival-based isochrone searches with specific arrival times.
                             Max 10 searches.
            departure_searches: Departure-based isochrone searches with specific departure times.
                               Max 10 searches.

        Returns:
            TimeMapWKTResponse: Detailed polygon geometries in WKT format including
                               holes and complex shapes for GIS processing.
        """
        return self._api_call_post(
            TimeMapWKTResponse,
            "time-map",
            AcceptType.WKT,
            TimeMapWktRequest(
                arrival_searches=arrival_searches, departure_searches=departure_searches
            ),
        )

    def time_map_wkt_no_holes(
        self,
        arrival_searches: List[TimeMapArrivalSearch],
        departure_searches: List[TimeMapDepartureSearch],
    ) -> TimeMapWKTResponse:
        """Generate comprehensive travel time isochrones in simplified WKT format.

        Creates travel time catchment area polygons in WKT format without holes,
        providing simplified geometries with full configurability.

        Args:
            arrival_searches: Arrival-based isochrone searches with specific arrival times.
                             Max 10 searches.
            departure_searches: Departure-based isochrone searches with specific departure times.
                               Max 10 searches.

        Returns:
            TimeMapWKTResponse: Simplified polygon geometries in WKT format without
                               holes or islands for easier processing.
        """
        return self._api_call_post(
            TimeMapWKTResponse,
            "time-map",
            AcceptType.WKT_NO_HOLES,
            TimeMapWktRequest(
                arrival_searches=arrival_searches, departure_searches=departure_searches
            ),
        )

    def time_map_fast(
        self,
        arrival_searches: TimeMapFastArrivalSearches,
    ) -> TimeMapResponse:
        """Generate high-performance travel time isochrones in JSON format.

        Creates travel time catchment area polygons showing all locations reachable
        within specified travel times. Returns standard JSON response format.

        Args:
            arrival_searches: Isochrone search configurations with many_to_one and one_to_many patterns.
                              Max 10 searches total.

        Returns:
            TimeMapResponse: Polygon coordinates and metadata in JSON format for map visualization and processing.
        """
        return self._api_call_post(
            TimeMapResponse,
            "time-map/fast",
            AcceptType.JSON,
            TimeMapFastRequest(arrival_searches=arrival_searches),
        )

    def time_map_fast_geojson(
        self,
        arrival_searches: TimeMapFastArrivalSearches,
    ) -> FeatureCollection:
        """Generate high-performance travel time isochrones in GeoJSON format.

        Creates travel time catchment area polygons in GeoJSON format, optimized
        for direct use with mapping libraries like Leaflet, Mapbox, and OpenLayers.

        Args:
            arrival_searches: Isochrone search configurations with many_to_one and
                             one_to_many patterns. Max 10 searches total.

        Returns:
            FeatureCollection: GeoJSON FeatureCollection with polygon geometries
                              ready for mapping library integration.
        """
        return self._api_call_post(
            FeatureCollection,
            "time-map/fast",
            AcceptType.GEO_JSON,
            TimeMapFastGeojsonRequest(arrival_searches=arrival_searches),
        )

    def time_map_fast_wkt(
        self,
        arrival_searches: TimeMapFastArrivalSearches,
    ) -> TimeMapWKTResponse:
        """Generate high-performance travel time isochrones in WKT format.

        Creates travel time catchment area polygons in Well-Known Text format,
        suitable for GIS applications and spatial databases.

        Args:
            arrival_searches: Isochrone search configurations with many_to_one and
                             one_to_many patterns. Max 10 searches total.

        Returns:
            TimeMapWKTResponse: Polygon geometries in WKT format for GIS processing
                               and spatial database storage.
        """
        return self._api_call_post(
            TimeMapWKTResponse,
            "time-map/fast",
            AcceptType.WKT,
            TimeMapFastWKTRequest(arrival_searches=arrival_searches),
        )

    def time_map_fast_wkt_no_holes(
        self,
        arrival_searches: TimeMapFastArrivalSearches,
    ) -> TimeMapWKTResponse:
        """Generate high-performance travel time isochrones in simplified WKT format.

        Creates travel time catchment area polygons in WKT format without holes,
        providing simplified geometries for applications that don't support complex polygons.

        Args:
            arrival_searches: Isochrone search configurations with many_to_one and
                             one_to_many patterns. Max 10 searches total.

        Returns:
            TimeMapWKTResponse: Simplified polygon geometries in WKT format without
                               holes or islands for easier processing.
        """
        return self._api_call_post(
            TimeMapWKTResponse,
            "time-map/fast",
            AcceptType.WKT_NO_HOLES,
            TimeMapFastWKTRequest(arrival_searches=arrival_searches),
        )

    def h3(
        self,
        arrival_searches: List[H3ArrivalSearch],
        departure_searches: List[H3DepartureSearch],
        properties: List[CellProperty],
        resolution: int,
        unions: List[H3Union],
        intersections: List[H3Intersection],
    ) -> H3Response:
        """Standard H3 endpoint with comprehensive features including specific
        departure/arrival times, unions, and intersections of search results.

        Args:
            arrival_searches: Arrival-based searches with specific arrival times
            departure_searches: Departure-based searches with specific departure times
            properties: Statistical properties to calculate ('min', 'max', 'mean')
            resolution: H3 resolution level (higher = more granular cells).
                         Limitations can be found here:
                         https://docs.traveltime.com/api/reference/h3#limits-of-resolution-and-traveltime.
            unions: Union operations combining multiple search results
            intersections: Intersection operations finding overlapping areas

        Returns:
            Travel time statistics for H3 cells in catchment areas.
        """

        return self._api_call_post(
            H3Response,
            "h3",
            AcceptType.JSON,
            H3Request(
                resolution=resolution,
                properties=properties,
                departure_searches=departure_searches,
                arrival_searches=arrival_searches,
                unions=unions,
                intersections=intersections,
            ),
        )

    def h3_fast(
        self,
        arrival_searches: H3FastArrivalSearches,
        properties: List[CellProperty],
        resolution: int,
        unions: List[H3FastUnion],
        intersections: List[H3FastIntersection],
    ) -> H3Response:
        """Calculate travel times to H3 cells within travel time catchment areas.

        High-performance endpoint that returns min/max/mean travel times for H3 hexagonal
        cells based on arrival searches with support for unions and intersections.

        Args:
            arrival_searches: Search configurations with arrival points and transportation methods.
                              Max 10 searches per request.
            properties: Statistical properties to calculate ('min', 'max', 'mean').
            resolution: H3 resolution level (higher = more granular cells).
                         Limitations can be found here:
                         https://docs.traveltime.com/api/reference/h3-fast#limits-of-resolution-and-traveltime.
            unions: Union operations combining multiple search results
            intersections: Intersection operations finding overlapping areas

        Returns:
            H3Response: Travel time statistics for H3 cells in catchment areas.
        """

        return self._api_call_post(
            H3Response,
            "h3/fast",
            AcceptType.JSON,
            H3FastRequest(
                resolution=resolution,
                properties=properties,
                arrival_searches=arrival_searches,
                unions=unions,
                intersections=intersections,
            ),
        )

    def geohash(
        self,
        arrival_searches: List[GeoHashArrivalSearch],
        departure_searches: List[GeoHashDepartureSearch],
        properties: List[CellProperty],
        resolution: int,
        unions: List[GeoHashUnion],
        intersections: List[GeoHashIntersection],
    ) -> GeoHashResponse:
        """Calculate travel times to geohash cells within travel time catchment areas.

        Returns min, max, and mean travel times for each geohash cell. This is a more
        configurable version of geohash-fast but with lower performance.

        Args:
            arrival_searches: List of arrival-based searches calculating travel times
                             from geohash cells to specific destinations.

            departure_searches: List of departure-based searches calculating travel times
                               from specific origins to geohash cells.

            properties: List of travel time properties to calculate for each cell.
                       Options include minimum, maximum, and mean travel times.

            resolution: Geohash resolution of results to be returned.
                       Valid range: 1-6, where higher values provide more precise areas.

            unions: List of union operations combining multiple searches to show
                   total coverage across multiple access points.

            intersections: List of intersection operations finding cells that satisfy
                          multiple accessibility criteria simultaneously.

        Returns:
            GeoHashResponse containing travel time statistics for each geohash cell
            within the reachable area.
        """

        return self._api_call_post(
            GeoHashResponse,
            "geohash",
            AcceptType.JSON,
            GeoHashRequest(
                resolution=resolution,
                properties=properties,
                departure_searches=departure_searches,
                arrival_searches=arrival_searches,
                unions=unions,
                intersections=intersections,
            ),
        )

    def geohash_fast(
        self,
        arrival_searches: GeoHashFastArrivalSearches,
        properties: List[CellProperty],
        resolution: int,
        unions: List[GeoHashFastUnion],
        intersections: List[GeoHashFastIntersection],
    ) -> GeoHashResponse:
        """High-performance version of geohash search with fewer configurable parameters
        and more limited geographic coverage. Returns statistical travel time measures
        for each geohash cell.

        Args:
            arrival_searches: Arrival-based search configurations containing
                             many-to-one and one-to-many search definitions.

            properties: List of travel time properties to calculate for each cell.
                       Options include minimum, maximum, and mean travel times.

            resolution: Geohash resolution of results to be returned.
                       Valid range: 1-6, where higher values provide more precise areas.

            unions: Union operations combining multiple search results
            intersections: Intersection operations finding overlapping areas

        Returns:
            GeoHashResponse containing travel time statistics for each geohash cell
            within the reachable area.
        """
        return self._api_call_post(
            GeoHashResponse,
            "geohash/fast",
            AcceptType.JSON,
            GeoHashFastRequest(
                resolution=resolution,
                properties=properties,
                arrival_searches=arrival_searches,
                unions=unions,
                intersections=intersections,
            ),
        )

    def postcodes(
        self,
        arrival_searches: List[PostcodeArrivalSearch],
        departure_searches: List[PostcodeDepartureSearch],
    ) -> PostcodesResponse:
        """Find reachable UK postcodes and get travel statistics.

        Searches for postcodes within travel time catchments and returns travel time
        and distance data. Currently only supports United Kingdom postcodes.

        Args:
            arrival_searches: Arrival-based searches finding postcodes that can reach
                             specific destinations. Max 10 searches.
            departure_searches: Departure-based searches finding postcodes reachable
                               from specific origins. Max 10 searches.

        Returns:
            PostcodesResponse: Travel statistics for reachable postcodes including
                              travel times and distances based on requested properties.
        """

        return self._api_call_post(
            PostcodesResponse,
            "time-filter/postcodes",
            AcceptType.JSON,
            PostcodesRequest(
                arrival_searches=arrival_searches, departure_searches=departure_searches
            ),
        )

    def postcode_districts(
        self,
        arrival_searches: List[PostcodeFilterArrivalSearch],
        departure_searches: List[PostcodeFilterDepartureSearch],
    ) -> PostcodesDistrictsResponse:
        """Searches for postcode districts based on coverage thresholds (percentage of
        reachable postcodes within districts). Districts are broader geographic areas
        than sectors. Currently only supports United Kingdom.

        Args:
            arrival_searches: Arrival-based searches with coverage filtering for districts
                             that can reach specific destinations. Max 10 searches.
            departure_searches: Departure-based searches with coverage filtering for districts
                               reachable from specific origins. Max 10 searches.

        Returns:
            PostcodesDistrictsResponse: Statistics for postcode districts including
                                       travel times and coverage percentages.
        """

        return self._api_call_post(
            PostcodesDistrictsResponse,
            "time-filter/postcode-districts",
            AcceptType.JSON,
            PostcodesDistrictsRequest(
                arrival_searches=arrival_searches, departure_searches=departure_searches
            ),
        )

    def postcode_sectors(
        self,
        arrival_searches: List[PostcodeFilterArrivalSearch],
        departure_searches: List[PostcodeFilterDepartureSearch],
    ) -> PostcodesSectorsResponse:
        """Searches for postcode sectors based on coverage thresholds (percentage of
        reachable postcodes within sectors). Sectors are more granular geographic areas
        than districts. Currently only supports United Kingdom.

        Args:
            arrival_searches: Arrival-based searches with coverage filtering for sectors
                             that can reach specific destinations. Max 10 searches.
            departure_searches: Departure-based searches with coverage filtering for sectors
                               reachable from specific origins. Max 10 searches.

        Returns:
            PostcodesSectorsResponse: Statistics for postcode sectors including
                                     travel times and coverage percentages.
        """

        return self._api_call_post(
            PostcodesSectorsResponse,
            "time-filter/postcode-sectors",
            AcceptType.JSON,
            PostcodesSectorsRequest(
                arrival_searches=arrival_searches, departure_searches=departure_searches
            ),
        )

    def routes(
        self,
        locations: List[Location],
        arrival_searches: List[RoutesArrivalSearch],
        departure_searches: List[RoutesDepartureSearch],
    ) -> RoutesResponse:
        """Calculate A to B routes with turn-by-turn directions.

        Returns detailed routing information between specific locations including
        turn-by-turn directions, travel times, distances, and fare information.

        Args:
            locations: List of all locations referenced by ID in searches
            arrival_searches: Arrival-based searches from multiple origins to one destination. Max 10 searches.
            departure_searches: Departure-based searches from one origin to multiple destinations. Max 10 searches.

        Returns:
            RoutesResponse: Detailed route information including turn-by-turn directions,
                           travel times, distances, and fares based on requested properties.
        """
        return self._api_call_post(
            RoutesResponse,
            "routes",
            AcceptType.JSON,
            RoutesRequest(
                locations=locations,
                departure_searches=departure_searches,
                arrival_searches=arrival_searches,
            ),
        )

    def distance_map(
        self,
        arrival_searches: List[DistanceMapArrivalSearch],
        departure_searches: List[DistanceMapDepartureSearch],
        unions: List[DistanceMapUnion],
        intersections: List[DistanceMapIntersection],
    ) -> TimeMapResponse:
        """Generate distance maps (isodistance polygons) showing areas reachable within
        specified travel distances.

        Creates polygon shapes representing all areas reachable within a travel distance limit
        from departure points or areas that can reach arrival points within distance constraints.
        Supports combining results through union and intersection operations.

        Args:
            arrival_searches: List of arrival-based searches showing areas that can reach
                             specific destinations within travel distance limits.

            departure_searches: List of departure-based searches showing areas reachable
                               from specific starting points within travel distance limits.

            unions: List of union operations combining multiple searches to show
                   total coverage areas across multiple access points.

            intersections: List of intersection operations finding areas that satisfy
                          multiple accessibility criteria simultaneously.

        Returns:
            TimeMapResponse containing polygon shapes for each search operation,
            with results sorted lexicographically by search_id.
        """

        return self._api_call_post(
            TimeMapResponse,
            "distance-map",
            AcceptType.JSON,
            DistanceMapRequest(
                departure_searches=departure_searches,
                arrival_searches=arrival_searches,
                unions=unions,
                intersections=intersections,
            ),
        )
