# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

from __future__ import annotations

from typing import Iterable

import httpx

from .steps import (
    StepsResource,
    AsyncStepsResource,
    StepsResourceWithRawResponse,
    AsyncStepsResourceWithRawResponse,
    StepsResourceWithStreamingResponse,
    AsyncStepsResourceWithStreamingResponse,
)
from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven
from ...._utils import maybe_transform, async_maybe_transform
from ...._compat import cached_property
from ...._resource import SyncAPIResource, AsyncAPIResource
from ...._response import (
    to_raw_response_wrapper,
    to_streamed_response_wrapper,
    async_to_raw_response_wrapper,
    async_to_streamed_response_wrapper,
)
from ...._base_client import make_request_options
from ....types.fleetify import route_create_params, route_redispatch_params
from ....types.fleetify.route_create_response import RouteCreateResponse
from ....types.fleetify.route_redispatch_response import RouteRedispatchResponse
from ....types.fleetify.routes.route_steps_request_param import RouteStepsRequestParam

__all__ = ["RoutesResource", "AsyncRoutesResource"]


class RoutesResource(SyncAPIResource):
    @cached_property
    def steps(self) -> StepsResource:
        return StepsResource(self._client)

    @cached_property
    def with_raw_response(self) -> RoutesResourceWithRawResponse:
        """
        This property can be used as a prefix for any HTTP method call to return
        the raw response object instead of the parsed content.

        For more information, see https://www.github.com/nextbillion-ai/nextbillion-sdk-python#accessing-raw-response-data-eg-headers
        """
        return RoutesResourceWithRawResponse(self)

    @cached_property
    def with_streaming_response(self) -> RoutesResourceWithStreamingResponse:
        """
        An alternative to `.with_raw_response` that doesn't eagerly read the response body.

        For more information, see https://www.github.com/nextbillion-ai/nextbillion-sdk-python#with_streaming_response
        """
        return RoutesResourceWithStreamingResponse(self)

    def create(
        self,
        *,
        key: str,
        driver_email: str,
        steps: Iterable[RouteStepsRequestParam],
        distance: int | NotGiven = NOT_GIVEN,
        document_template_id: str | NotGiven = NOT_GIVEN,
        ro_request_id: str | NotGiven = NOT_GIVEN,
        routing: route_create_params.Routing | NotGiven = NOT_GIVEN,
        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
        # The extra values given here take precedence over values defined on the client or passed to this method.
        extra_headers: Headers | None = None,
        extra_query: Query | None = None,
        extra_body: Body | None = None,
        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
    ) -> RouteCreateResponse:
        """
        Dispatch a new route

        Args:
          key: A key is a unique identifier that is required to authenticate a request to the
              API.

          driver_email: Specify the e-mail address of the driver who should receive the route. The
              e-mail address must be registered in
              [NextBillion.ai Cloud Console](https://console.nextbillion.ai/).

          steps: An array of objects to collect the details about the intermediate steps in the
              route to be dispatched. Each object corresponds to a single step. The array must
              begin with a start-type step and end with an end-type step, to form a valid
              route.

          distance: Specify the total distance, in meters, for an informative display in Driver's
              app. The distance specified here has no effect on the actual route that the
              service generates.

          document_template_id: Specify the ID of the document template that should be used to collect proof of
              completion for all steps in the route. In order to complete each route step, the
              driver will need to submit a form generated by the rules defined in the given
              document template. Use the
              [Documents API](https://docs.nextbillion.ai/docs/dispatches/documents-api) to
              create, read and manage document templates.

              Please note that the document template ID assigned to a route does not apply to
              following step types - `start`, `end`, `break`, `layover`.

          ro_request_id: Specify the Route Optimization request ID. When this ID is provided, all other
              fields will be ignored (including the required fields) and the route
              optimization result will be used to form the routes and corresponding steps.

              Please note that:

              - The driver's email ID must be provided in input `vehicle.metadata` as
                `user_email` such that the route optimization result must contain a valid
                driver email, step's arrival time, etc., to make a successful dispatch.
              - Document Template for collecting proof of delivery or completion can not be
                specified when using this field to dispatch a route.
              - In case of an error at any part among the routes, the API will immediately
                return the error with the index of the specific route or route step.
              - On a successful dispatch, the API returns the last route, if there are many,
                in the response payload.

          routing: The `routing` object allows defining the routing characteristics that should be
              used to generate a route when the Driver uses the in-app navigation. Only `car`
              mode is supported currently.

          extra_headers: Send extra headers

          extra_query: Add additional query parameters to the request

          extra_body: Add additional JSON properties to the request

          timeout: Override the client-level default timeout for this request, in seconds
        """
        return self._post(
            "/fleetify/routes",
            body=maybe_transform(
                {
                    "driver_email": driver_email,
                    "steps": steps,
                    "distance": distance,
                    "document_template_id": document_template_id,
                    "ro_request_id": ro_request_id,
                    "routing": routing,
                },
                route_create_params.RouteCreateParams,
            ),
            options=make_request_options(
                extra_headers=extra_headers,
                extra_query=extra_query,
                extra_body=extra_body,
                timeout=timeout,
                query=maybe_transform({"key": key}, route_create_params.RouteCreateParams),
            ),
            cast_to=RouteCreateResponse,
        )

    def redispatch(
        self,
        route_id: str,
        *,
        key: str,
        operations: Iterable[route_redispatch_params.Operation],
        distance: float | NotGiven = NOT_GIVEN,
        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
        # The extra values given here take precedence over values defined on the client or passed to this method.
        extra_headers: Headers | None = None,
        extra_query: Query | None = None,
        extra_body: Body | None = None,
        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
    ) -> RouteRedispatchResponse:
        """
        Re-dispatch route

        Args:
          key: A key is a unique identifier that is required to authenticate a request to the
              API.

          operations: A collection of objects with details of the steps to be modified. Each object
              corresponds to a single step.

          distance: Specify the distance of the route.

          extra_headers: Send extra headers

          extra_query: Add additional query parameters to the request

          extra_body: Add additional JSON properties to the request

          timeout: Override the client-level default timeout for this request, in seconds
        """
        if not route_id:
            raise ValueError(f"Expected a non-empty value for `route_id` but received {route_id!r}")
        return self._post(
            f"/fleetify/routes/{route_id}/redispatch",
            body=maybe_transform(
                {
                    "operations": operations,
                    "distance": distance,
                },
                route_redispatch_params.RouteRedispatchParams,
            ),
            options=make_request_options(
                extra_headers=extra_headers,
                extra_query=extra_query,
                extra_body=extra_body,
                timeout=timeout,
                query=maybe_transform({"key": key}, route_redispatch_params.RouteRedispatchParams),
            ),
            cast_to=RouteRedispatchResponse,
        )


class AsyncRoutesResource(AsyncAPIResource):
    @cached_property
    def steps(self) -> AsyncStepsResource:
        return AsyncStepsResource(self._client)

    @cached_property
    def with_raw_response(self) -> AsyncRoutesResourceWithRawResponse:
        """
        This property can be used as a prefix for any HTTP method call to return
        the raw response object instead of the parsed content.

        For more information, see https://www.github.com/nextbillion-ai/nextbillion-sdk-python#accessing-raw-response-data-eg-headers
        """
        return AsyncRoutesResourceWithRawResponse(self)

    @cached_property
    def with_streaming_response(self) -> AsyncRoutesResourceWithStreamingResponse:
        """
        An alternative to `.with_raw_response` that doesn't eagerly read the response body.

        For more information, see https://www.github.com/nextbillion-ai/nextbillion-sdk-python#with_streaming_response
        """
        return AsyncRoutesResourceWithStreamingResponse(self)

    async def create(
        self,
        *,
        key: str,
        driver_email: str,
        steps: Iterable[RouteStepsRequestParam],
        distance: int | NotGiven = NOT_GIVEN,
        document_template_id: str | NotGiven = NOT_GIVEN,
        ro_request_id: str | NotGiven = NOT_GIVEN,
        routing: route_create_params.Routing | NotGiven = NOT_GIVEN,
        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
        # The extra values given here take precedence over values defined on the client or passed to this method.
        extra_headers: Headers | None = None,
        extra_query: Query | None = None,
        extra_body: Body | None = None,
        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
    ) -> RouteCreateResponse:
        """
        Dispatch a new route

        Args:
          key: A key is a unique identifier that is required to authenticate a request to the
              API.

          driver_email: Specify the e-mail address of the driver who should receive the route. The
              e-mail address must be registered in
              [NextBillion.ai Cloud Console](https://console.nextbillion.ai/).

          steps: An array of objects to collect the details about the intermediate steps in the
              route to be dispatched. Each object corresponds to a single step. The array must
              begin with a start-type step and end with an end-type step, to form a valid
              route.

          distance: Specify the total distance, in meters, for an informative display in Driver's
              app. The distance specified here has no effect on the actual route that the
              service generates.

          document_template_id: Specify the ID of the document template that should be used to collect proof of
              completion for all steps in the route. In order to complete each route step, the
              driver will need to submit a form generated by the rules defined in the given
              document template. Use the
              [Documents API](https://docs.nextbillion.ai/docs/dispatches/documents-api) to
              create, read and manage document templates.

              Please note that the document template ID assigned to a route does not apply to
              following step types - `start`, `end`, `break`, `layover`.

          ro_request_id: Specify the Route Optimization request ID. When this ID is provided, all other
              fields will be ignored (including the required fields) and the route
              optimization result will be used to form the routes and corresponding steps.

              Please note that:

              - The driver's email ID must be provided in input `vehicle.metadata` as
                `user_email` such that the route optimization result must contain a valid
                driver email, step's arrival time, etc., to make a successful dispatch.
              - Document Template for collecting proof of delivery or completion can not be
                specified when using this field to dispatch a route.
              - In case of an error at any part among the routes, the API will immediately
                return the error with the index of the specific route or route step.
              - On a successful dispatch, the API returns the last route, if there are many,
                in the response payload.

          routing: The `routing` object allows defining the routing characteristics that should be
              used to generate a route when the Driver uses the in-app navigation. Only `car`
              mode is supported currently.

          extra_headers: Send extra headers

          extra_query: Add additional query parameters to the request

          extra_body: Add additional JSON properties to the request

          timeout: Override the client-level default timeout for this request, in seconds
        """
        return await self._post(
            "/fleetify/routes",
            body=await async_maybe_transform(
                {
                    "driver_email": driver_email,
                    "steps": steps,
                    "distance": distance,
                    "document_template_id": document_template_id,
                    "ro_request_id": ro_request_id,
                    "routing": routing,
                },
                route_create_params.RouteCreateParams,
            ),
            options=make_request_options(
                extra_headers=extra_headers,
                extra_query=extra_query,
                extra_body=extra_body,
                timeout=timeout,
                query=await async_maybe_transform({"key": key}, route_create_params.RouteCreateParams),
            ),
            cast_to=RouteCreateResponse,
        )

    async def redispatch(
        self,
        route_id: str,
        *,
        key: str,
        operations: Iterable[route_redispatch_params.Operation],
        distance: float | NotGiven = NOT_GIVEN,
        # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
        # The extra values given here take precedence over values defined on the client or passed to this method.
        extra_headers: Headers | None = None,
        extra_query: Query | None = None,
        extra_body: Body | None = None,
        timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
    ) -> RouteRedispatchResponse:
        """
        Re-dispatch route

        Args:
          key: A key is a unique identifier that is required to authenticate a request to the
              API.

          operations: A collection of objects with details of the steps to be modified. Each object
              corresponds to a single step.

          distance: Specify the distance of the route.

          extra_headers: Send extra headers

          extra_query: Add additional query parameters to the request

          extra_body: Add additional JSON properties to the request

          timeout: Override the client-level default timeout for this request, in seconds
        """
        if not route_id:
            raise ValueError(f"Expected a non-empty value for `route_id` but received {route_id!r}")
        return await self._post(
            f"/fleetify/routes/{route_id}/redispatch",
            body=await async_maybe_transform(
                {
                    "operations": operations,
                    "distance": distance,
                },
                route_redispatch_params.RouteRedispatchParams,
            ),
            options=make_request_options(
                extra_headers=extra_headers,
                extra_query=extra_query,
                extra_body=extra_body,
                timeout=timeout,
                query=await async_maybe_transform({"key": key}, route_redispatch_params.RouteRedispatchParams),
            ),
            cast_to=RouteRedispatchResponse,
        )


class RoutesResourceWithRawResponse:
    def __init__(self, routes: RoutesResource) -> None:
        self._routes = routes

        self.create = to_raw_response_wrapper(
            routes.create,
        )
        self.redispatch = to_raw_response_wrapper(
            routes.redispatch,
        )

    @cached_property
    def steps(self) -> StepsResourceWithRawResponse:
        return StepsResourceWithRawResponse(self._routes.steps)


class AsyncRoutesResourceWithRawResponse:
    def __init__(self, routes: AsyncRoutesResource) -> None:
        self._routes = routes

        self.create = async_to_raw_response_wrapper(
            routes.create,
        )
        self.redispatch = async_to_raw_response_wrapper(
            routes.redispatch,
        )

    @cached_property
    def steps(self) -> AsyncStepsResourceWithRawResponse:
        return AsyncStepsResourceWithRawResponse(self._routes.steps)


class RoutesResourceWithStreamingResponse:
    def __init__(self, routes: RoutesResource) -> None:
        self._routes = routes

        self.create = to_streamed_response_wrapper(
            routes.create,
        )
        self.redispatch = to_streamed_response_wrapper(
            routes.redispatch,
        )

    @cached_property
    def steps(self) -> StepsResourceWithStreamingResponse:
        return StepsResourceWithStreamingResponse(self._routes.steps)


class AsyncRoutesResourceWithStreamingResponse:
    def __init__(self, routes: AsyncRoutesResource) -> None:
        self._routes = routes

        self.create = async_to_streamed_response_wrapper(
            routes.create,
        )
        self.redispatch = async_to_streamed_response_wrapper(
            routes.redispatch,
        )

    @cached_property
    def steps(self) -> AsyncStepsResourceWithStreamingResponse:
        return AsyncStepsResourceWithStreamingResponse(self._routes.steps)
