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

from __future__ import annotations

import os
from typing import TYPE_CHECKING, Any, Mapping
from typing_extensions import Self, override

import httpx

from . import _exceptions
from ._qs import Querystring
from ._types import (
    Omit,
    Timeout,
    NotGiven,
    Transport,
    ProxiesTypes,
    RequestOptions,
    not_given,
)
from ._utils import is_given, get_async_library
from ._compat import cached_property
from ._version import __version__
from ._streaming import Stream as Stream, AsyncStream as AsyncStream
from ._exceptions import APIStatusError, NotiflowsError
from ._base_client import (
    DEFAULT_MAX_RETRIES,
    SyncAPIClient,
    AsyncAPIClient,
)

if TYPE_CHECKING:
    from .resources import users, topics, notiflows, deliveries, notifications
    from .resources.notiflows import NotiflowsResource, AsyncNotiflowsResource
    from .resources.deliveries import DeliveriesResource, AsyncDeliveriesResource
    from .resources.users.users import UsersResource, AsyncUsersResource
    from .resources.notifications import NotificationsResource, AsyncNotificationsResource
    from .resources.topics.topics import TopicsResource, AsyncTopicsResource

__all__ = [
    "Timeout",
    "Transport",
    "ProxiesTypes",
    "RequestOptions",
    "Notiflows",
    "AsyncNotiflows",
    "Client",
    "AsyncClient",
]


class Notiflows(SyncAPIClient):
    # client options
    api_key: str
    secret: str

    def __init__(
        self,
        *,
        api_key: str | None = None,
        secret: str | None = None,
        base_url: str | httpx.URL | None = None,
        timeout: float | Timeout | None | NotGiven = not_given,
        max_retries: int = DEFAULT_MAX_RETRIES,
        default_headers: Mapping[str, str] | None = None,
        default_query: Mapping[str, object] | None = None,
        # Configure a custom httpx client.
        # We provide a `DefaultHttpxClient` class that you can pass to retain the default values we use for `limits`, `timeout` & `follow_redirects`.
        # See the [httpx documentation](https://www.python-httpx.org/api/#client) for more details.
        http_client: httpx.Client | None = None,
        # Enable or disable schema validation for data returned by the API.
        # When enabled an error APIResponseValidationError is raised
        # if the API responds with invalid data for the expected schema.
        #
        # This parameter may be removed or changed in the future.
        # If you rely on this feature, please open a GitHub issue
        # outlining your use-case to help us decide if it should be
        # part of our public interface in the future.
        _strict_response_validation: bool = False,
    ) -> None:
        """Construct a new synchronous Notiflows client instance.

        This automatically infers the following arguments from their corresponding environment variables if they are not provided:
        - `api_key` from `NOTIFLOWS_SDK_API_KEY`
        - `secret` from `NOTIFLOWS_SDK_SECRET`
        """
        if api_key is None:
            api_key = os.environ.get("NOTIFLOWS_SDK_API_KEY")
        if api_key is None:
            raise NotiflowsError(
                "The api_key client option must be set either by passing api_key to the client or by setting the NOTIFLOWS_SDK_API_KEY environment variable"
            )
        self.api_key = api_key

        if secret is None:
            secret = os.environ.get("NOTIFLOWS_SDK_SECRET")
        if secret is None:
            raise NotiflowsError(
                "The secret client option must be set either by passing secret to the client or by setting the NOTIFLOWS_SDK_SECRET environment variable"
            )
        self.secret = secret

        if base_url is None:
            base_url = os.environ.get("NOTIFLOWS_BASE_URL")
        if base_url is None:
            base_url = f"https://api.notiflows.com/admin/v1"

        super().__init__(
            version=__version__,
            base_url=base_url,
            max_retries=max_retries,
            timeout=timeout,
            http_client=http_client,
            custom_headers=default_headers,
            custom_query=default_query,
            _strict_response_validation=_strict_response_validation,
        )

    @cached_property
    def deliveries(self) -> DeliveriesResource:
        from .resources.deliveries import DeliveriesResource

        return DeliveriesResource(self)

    @cached_property
    def notifications(self) -> NotificationsResource:
        from .resources.notifications import NotificationsResource

        return NotificationsResource(self)

    @cached_property
    def notiflows(self) -> NotiflowsResource:
        from .resources.notiflows import NotiflowsResource

        return NotiflowsResource(self)

    @cached_property
    def topics(self) -> TopicsResource:
        from .resources.topics import TopicsResource

        return TopicsResource(self)

    @cached_property
    def users(self) -> UsersResource:
        from .resources.users import UsersResource

        return UsersResource(self)

    @cached_property
    def with_raw_response(self) -> NotiflowsWithRawResponse:
        return NotiflowsWithRawResponse(self)

    @cached_property
    def with_streaming_response(self) -> NotiflowsWithStreamedResponse:
        return NotiflowsWithStreamedResponse(self)

    @property
    @override
    def qs(self) -> Querystring:
        return Querystring(array_format="comma")

    @property
    @override
    def auth_headers(self) -> dict[str, str]:
        return {**self._api_key_auth, **self._secret_key_auth}

    @property
    def _api_key_auth(self) -> dict[str, str]:
        api_key = self.api_key
        return {"x-notiflows-api-key": api_key}

    @property
    def _secret_key_auth(self) -> dict[str, str]:
        secret = self.secret
        return {"x-notiflows-secret-key": secret}

    @property
    @override
    def default_headers(self) -> dict[str, str | Omit]:
        return {
            **super().default_headers,
            "X-Stainless-Async": "false",
            **self._custom_headers,
        }

    def copy(
        self,
        *,
        api_key: str | None = None,
        secret: str | None = None,
        base_url: str | httpx.URL | None = None,
        timeout: float | Timeout | None | NotGiven = not_given,
        http_client: httpx.Client | None = None,
        max_retries: int | NotGiven = not_given,
        default_headers: Mapping[str, str] | None = None,
        set_default_headers: Mapping[str, str] | None = None,
        default_query: Mapping[str, object] | None = None,
        set_default_query: Mapping[str, object] | None = None,
        _extra_kwargs: Mapping[str, Any] = {},
    ) -> Self:
        """
        Create a new client instance re-using the same options given to the current client with optional overriding.
        """
        if default_headers is not None and set_default_headers is not None:
            raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive")

        if default_query is not None and set_default_query is not None:
            raise ValueError("The `default_query` and `set_default_query` arguments are mutually exclusive")

        headers = self._custom_headers
        if default_headers is not None:
            headers = {**headers, **default_headers}
        elif set_default_headers is not None:
            headers = set_default_headers

        params = self._custom_query
        if default_query is not None:
            params = {**params, **default_query}
        elif set_default_query is not None:
            params = set_default_query

        http_client = http_client or self._client
        return self.__class__(
            api_key=api_key or self.api_key,
            secret=secret or self.secret,
            base_url=base_url or self.base_url,
            timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
            http_client=http_client,
            max_retries=max_retries if is_given(max_retries) else self.max_retries,
            default_headers=headers,
            default_query=params,
            **_extra_kwargs,
        )

    # Alias for `copy` for nicer inline usage, e.g.
    # client.with_options(timeout=10).foo.create(...)
    with_options = copy

    @override
    def _make_status_error(
        self,
        err_msg: str,
        *,
        body: object,
        response: httpx.Response,
    ) -> APIStatusError:
        if response.status_code == 400:
            return _exceptions.BadRequestError(err_msg, response=response, body=body)

        if response.status_code == 401:
            return _exceptions.AuthenticationError(err_msg, response=response, body=body)

        if response.status_code == 403:
            return _exceptions.PermissionDeniedError(err_msg, response=response, body=body)

        if response.status_code == 404:
            return _exceptions.NotFoundError(err_msg, response=response, body=body)

        if response.status_code == 409:
            return _exceptions.ConflictError(err_msg, response=response, body=body)

        if response.status_code == 422:
            return _exceptions.UnprocessableEntityError(err_msg, response=response, body=body)

        if response.status_code == 429:
            return _exceptions.RateLimitError(err_msg, response=response, body=body)

        if response.status_code >= 500:
            return _exceptions.InternalServerError(err_msg, response=response, body=body)
        return APIStatusError(err_msg, response=response, body=body)


class AsyncNotiflows(AsyncAPIClient):
    # client options
    api_key: str
    secret: str

    def __init__(
        self,
        *,
        api_key: str | None = None,
        secret: str | None = None,
        base_url: str | httpx.URL | None = None,
        timeout: float | Timeout | None | NotGiven = not_given,
        max_retries: int = DEFAULT_MAX_RETRIES,
        default_headers: Mapping[str, str] | None = None,
        default_query: Mapping[str, object] | None = None,
        # Configure a custom httpx client.
        # We provide a `DefaultAsyncHttpxClient` class that you can pass to retain the default values we use for `limits`, `timeout` & `follow_redirects`.
        # See the [httpx documentation](https://www.python-httpx.org/api/#asyncclient) for more details.
        http_client: httpx.AsyncClient | None = None,
        # Enable or disable schema validation for data returned by the API.
        # When enabled an error APIResponseValidationError is raised
        # if the API responds with invalid data for the expected schema.
        #
        # This parameter may be removed or changed in the future.
        # If you rely on this feature, please open a GitHub issue
        # outlining your use-case to help us decide if it should be
        # part of our public interface in the future.
        _strict_response_validation: bool = False,
    ) -> None:
        """Construct a new async AsyncNotiflows client instance.

        This automatically infers the following arguments from their corresponding environment variables if they are not provided:
        - `api_key` from `NOTIFLOWS_SDK_API_KEY`
        - `secret` from `NOTIFLOWS_SDK_SECRET`
        """
        if api_key is None:
            api_key = os.environ.get("NOTIFLOWS_SDK_API_KEY")
        if api_key is None:
            raise NotiflowsError(
                "The api_key client option must be set either by passing api_key to the client or by setting the NOTIFLOWS_SDK_API_KEY environment variable"
            )
        self.api_key = api_key

        if secret is None:
            secret = os.environ.get("NOTIFLOWS_SDK_SECRET")
        if secret is None:
            raise NotiflowsError(
                "The secret client option must be set either by passing secret to the client or by setting the NOTIFLOWS_SDK_SECRET environment variable"
            )
        self.secret = secret

        if base_url is None:
            base_url = os.environ.get("NOTIFLOWS_BASE_URL")
        if base_url is None:
            base_url = f"https://api.notiflows.com/admin/v1"

        super().__init__(
            version=__version__,
            base_url=base_url,
            max_retries=max_retries,
            timeout=timeout,
            http_client=http_client,
            custom_headers=default_headers,
            custom_query=default_query,
            _strict_response_validation=_strict_response_validation,
        )

    @cached_property
    def deliveries(self) -> AsyncDeliveriesResource:
        from .resources.deliveries import AsyncDeliveriesResource

        return AsyncDeliveriesResource(self)

    @cached_property
    def notifications(self) -> AsyncNotificationsResource:
        from .resources.notifications import AsyncNotificationsResource

        return AsyncNotificationsResource(self)

    @cached_property
    def notiflows(self) -> AsyncNotiflowsResource:
        from .resources.notiflows import AsyncNotiflowsResource

        return AsyncNotiflowsResource(self)

    @cached_property
    def topics(self) -> AsyncTopicsResource:
        from .resources.topics import AsyncTopicsResource

        return AsyncTopicsResource(self)

    @cached_property
    def users(self) -> AsyncUsersResource:
        from .resources.users import AsyncUsersResource

        return AsyncUsersResource(self)

    @cached_property
    def with_raw_response(self) -> AsyncNotiflowsWithRawResponse:
        return AsyncNotiflowsWithRawResponse(self)

    @cached_property
    def with_streaming_response(self) -> AsyncNotiflowsWithStreamedResponse:
        return AsyncNotiflowsWithStreamedResponse(self)

    @property
    @override
    def qs(self) -> Querystring:
        return Querystring(array_format="comma")

    @property
    @override
    def auth_headers(self) -> dict[str, str]:
        return {**self._api_key_auth, **self._secret_key_auth}

    @property
    def _api_key_auth(self) -> dict[str, str]:
        api_key = self.api_key
        return {"x-notiflows-api-key": api_key}

    @property
    def _secret_key_auth(self) -> dict[str, str]:
        secret = self.secret
        return {"x-notiflows-secret-key": secret}

    @property
    @override
    def default_headers(self) -> dict[str, str | Omit]:
        return {
            **super().default_headers,
            "X-Stainless-Async": f"async:{get_async_library()}",
            **self._custom_headers,
        }

    def copy(
        self,
        *,
        api_key: str | None = None,
        secret: str | None = None,
        base_url: str | httpx.URL | None = None,
        timeout: float | Timeout | None | NotGiven = not_given,
        http_client: httpx.AsyncClient | None = None,
        max_retries: int | NotGiven = not_given,
        default_headers: Mapping[str, str] | None = None,
        set_default_headers: Mapping[str, str] | None = None,
        default_query: Mapping[str, object] | None = None,
        set_default_query: Mapping[str, object] | None = None,
        _extra_kwargs: Mapping[str, Any] = {},
    ) -> Self:
        """
        Create a new client instance re-using the same options given to the current client with optional overriding.
        """
        if default_headers is not None and set_default_headers is not None:
            raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive")

        if default_query is not None and set_default_query is not None:
            raise ValueError("The `default_query` and `set_default_query` arguments are mutually exclusive")

        headers = self._custom_headers
        if default_headers is not None:
            headers = {**headers, **default_headers}
        elif set_default_headers is not None:
            headers = set_default_headers

        params = self._custom_query
        if default_query is not None:
            params = {**params, **default_query}
        elif set_default_query is not None:
            params = set_default_query

        http_client = http_client or self._client
        return self.__class__(
            api_key=api_key or self.api_key,
            secret=secret or self.secret,
            base_url=base_url or self.base_url,
            timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
            http_client=http_client,
            max_retries=max_retries if is_given(max_retries) else self.max_retries,
            default_headers=headers,
            default_query=params,
            **_extra_kwargs,
        )

    # Alias for `copy` for nicer inline usage, e.g.
    # client.with_options(timeout=10).foo.create(...)
    with_options = copy

    @override
    def _make_status_error(
        self,
        err_msg: str,
        *,
        body: object,
        response: httpx.Response,
    ) -> APIStatusError:
        if response.status_code == 400:
            return _exceptions.BadRequestError(err_msg, response=response, body=body)

        if response.status_code == 401:
            return _exceptions.AuthenticationError(err_msg, response=response, body=body)

        if response.status_code == 403:
            return _exceptions.PermissionDeniedError(err_msg, response=response, body=body)

        if response.status_code == 404:
            return _exceptions.NotFoundError(err_msg, response=response, body=body)

        if response.status_code == 409:
            return _exceptions.ConflictError(err_msg, response=response, body=body)

        if response.status_code == 422:
            return _exceptions.UnprocessableEntityError(err_msg, response=response, body=body)

        if response.status_code == 429:
            return _exceptions.RateLimitError(err_msg, response=response, body=body)

        if response.status_code >= 500:
            return _exceptions.InternalServerError(err_msg, response=response, body=body)
        return APIStatusError(err_msg, response=response, body=body)


class NotiflowsWithRawResponse:
    _client: Notiflows

    def __init__(self, client: Notiflows) -> None:
        self._client = client

    @cached_property
    def deliveries(self) -> deliveries.DeliveriesResourceWithRawResponse:
        from .resources.deliveries import DeliveriesResourceWithRawResponse

        return DeliveriesResourceWithRawResponse(self._client.deliveries)

    @cached_property
    def notifications(self) -> notifications.NotificationsResourceWithRawResponse:
        from .resources.notifications import NotificationsResourceWithRawResponse

        return NotificationsResourceWithRawResponse(self._client.notifications)

    @cached_property
    def notiflows(self) -> notiflows.NotiflowsResourceWithRawResponse:
        from .resources.notiflows import NotiflowsResourceWithRawResponse

        return NotiflowsResourceWithRawResponse(self._client.notiflows)

    @cached_property
    def topics(self) -> topics.TopicsResourceWithRawResponse:
        from .resources.topics import TopicsResourceWithRawResponse

        return TopicsResourceWithRawResponse(self._client.topics)

    @cached_property
    def users(self) -> users.UsersResourceWithRawResponse:
        from .resources.users import UsersResourceWithRawResponse

        return UsersResourceWithRawResponse(self._client.users)


class AsyncNotiflowsWithRawResponse:
    _client: AsyncNotiflows

    def __init__(self, client: AsyncNotiflows) -> None:
        self._client = client

    @cached_property
    def deliveries(self) -> deliveries.AsyncDeliveriesResourceWithRawResponse:
        from .resources.deliveries import AsyncDeliveriesResourceWithRawResponse

        return AsyncDeliveriesResourceWithRawResponse(self._client.deliveries)

    @cached_property
    def notifications(self) -> notifications.AsyncNotificationsResourceWithRawResponse:
        from .resources.notifications import AsyncNotificationsResourceWithRawResponse

        return AsyncNotificationsResourceWithRawResponse(self._client.notifications)

    @cached_property
    def notiflows(self) -> notiflows.AsyncNotiflowsResourceWithRawResponse:
        from .resources.notiflows import AsyncNotiflowsResourceWithRawResponse

        return AsyncNotiflowsResourceWithRawResponse(self._client.notiflows)

    @cached_property
    def topics(self) -> topics.AsyncTopicsResourceWithRawResponse:
        from .resources.topics import AsyncTopicsResourceWithRawResponse

        return AsyncTopicsResourceWithRawResponse(self._client.topics)

    @cached_property
    def users(self) -> users.AsyncUsersResourceWithRawResponse:
        from .resources.users import AsyncUsersResourceWithRawResponse

        return AsyncUsersResourceWithRawResponse(self._client.users)


class NotiflowsWithStreamedResponse:
    _client: Notiflows

    def __init__(self, client: Notiflows) -> None:
        self._client = client

    @cached_property
    def deliveries(self) -> deliveries.DeliveriesResourceWithStreamingResponse:
        from .resources.deliveries import DeliveriesResourceWithStreamingResponse

        return DeliveriesResourceWithStreamingResponse(self._client.deliveries)

    @cached_property
    def notifications(self) -> notifications.NotificationsResourceWithStreamingResponse:
        from .resources.notifications import NotificationsResourceWithStreamingResponse

        return NotificationsResourceWithStreamingResponse(self._client.notifications)

    @cached_property
    def notiflows(self) -> notiflows.NotiflowsResourceWithStreamingResponse:
        from .resources.notiflows import NotiflowsResourceWithStreamingResponse

        return NotiflowsResourceWithStreamingResponse(self._client.notiflows)

    @cached_property
    def topics(self) -> topics.TopicsResourceWithStreamingResponse:
        from .resources.topics import TopicsResourceWithStreamingResponse

        return TopicsResourceWithStreamingResponse(self._client.topics)

    @cached_property
    def users(self) -> users.UsersResourceWithStreamingResponse:
        from .resources.users import UsersResourceWithStreamingResponse

        return UsersResourceWithStreamingResponse(self._client.users)


class AsyncNotiflowsWithStreamedResponse:
    _client: AsyncNotiflows

    def __init__(self, client: AsyncNotiflows) -> None:
        self._client = client

    @cached_property
    def deliveries(self) -> deliveries.AsyncDeliveriesResourceWithStreamingResponse:
        from .resources.deliveries import AsyncDeliveriesResourceWithStreamingResponse

        return AsyncDeliveriesResourceWithStreamingResponse(self._client.deliveries)

    @cached_property
    def notifications(self) -> notifications.AsyncNotificationsResourceWithStreamingResponse:
        from .resources.notifications import AsyncNotificationsResourceWithStreamingResponse

        return AsyncNotificationsResourceWithStreamingResponse(self._client.notifications)

    @cached_property
    def notiflows(self) -> notiflows.AsyncNotiflowsResourceWithStreamingResponse:
        from .resources.notiflows import AsyncNotiflowsResourceWithStreamingResponse

        return AsyncNotiflowsResourceWithStreamingResponse(self._client.notiflows)

    @cached_property
    def topics(self) -> topics.AsyncTopicsResourceWithStreamingResponse:
        from .resources.topics import AsyncTopicsResourceWithStreamingResponse

        return AsyncTopicsResourceWithStreamingResponse(self._client.topics)

    @cached_property
    def users(self) -> users.AsyncUsersResourceWithStreamingResponse:
        from .resources.users import AsyncUsersResourceWithStreamingResponse

        return AsyncUsersResourceWithStreamingResponse(self._client.users)


Client = Notiflows

AsyncClient = AsyncNotiflows
