# 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 Y2Error, APIStatusError
from ._base_client import (
    DEFAULT_MAX_RETRIES,
    SyncAPIClient,
    AsyncAPIClient,
)

if TYPE_CHECKING:
    from .resources import news, osint, reports, profiles, webhooks, subscriptions
    from .resources.news import NewsResource, AsyncNewsResource
    from .resources.reports import ReportsResource, AsyncReportsResource
    from .resources.profiles import ProfilesResource, AsyncProfilesResource
    from .resources.webhooks import WebhooksResource, AsyncWebhooksResource
    from .resources.osint.osint import OsintResource, AsyncOsintResource
    from .resources.subscriptions import SubscriptionsResource, AsyncSubscriptionsResource

__all__ = ["Timeout", "Transport", "ProxiesTypes", "RequestOptions", "Y2", "AsyncY2", "Client", "AsyncClient"]


class Y2(SyncAPIClient):
    # client options
    api_key: str

    def __init__(
        self,
        *,
        api_key: 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 Y2 client instance.

        This automatically infers the `api_key` argument from the `Y2_API_KEY` environment variable if it is not provided.
        """
        if api_key is None:
            api_key = os.environ.get("Y2_API_KEY")
        if api_key is None:
            raise Y2Error(
                "The api_key client option must be set either by passing api_key to the client or by setting the Y2_API_KEY environment variable"
            )
        self.api_key = api_key

        if base_url is None:
            base_url = os.environ.get("Y2_BASE_URL")
        if base_url is None:
            base_url = f"https://api.y2.dev/api/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 reports(self) -> ReportsResource:
        """Intelligence report operations"""
        from .resources.reports import ReportsResource

        return ReportsResource(self)

    @cached_property
    def profiles(self) -> ProfilesResource:
        """Subscription profile operations"""
        from .resources.profiles import ProfilesResource

        return ProfilesResource(self)

    @cached_property
    def news(self) -> NewsResource:
        """GloriaAI news terminal operations"""
        from .resources.news import NewsResource

        return NewsResource(self)

    @cached_property
    def webhooks(self) -> WebhooksResource:
        """Webhook configuration management (Pro feature)"""
        from .resources.webhooks import WebhooksResource

        return WebhooksResource(self)

    @cached_property
    def subscriptions(self) -> SubscriptionsResource:
        """Subscription delivery management"""
        from .resources.subscriptions import SubscriptionsResource

        return SubscriptionsResource(self)

    @cached_property
    def osint(self) -> OsintResource:
        """Situation Room OSINT intelligence operations"""
        from .resources.osint import OsintResource

        return OsintResource(self)

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

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

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

    @property
    @override
    def auth_headers(self) -> dict[str, str]:
        api_key = self.api_key
        return {"Authorization": f"Bearer {api_key}"}

    @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,
        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,
            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 AsyncY2(AsyncAPIClient):
    # client options
    api_key: str

    def __init__(
        self,
        *,
        api_key: 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 AsyncY2 client instance.

        This automatically infers the `api_key` argument from the `Y2_API_KEY` environment variable if it is not provided.
        """
        if api_key is None:
            api_key = os.environ.get("Y2_API_KEY")
        if api_key is None:
            raise Y2Error(
                "The api_key client option must be set either by passing api_key to the client or by setting the Y2_API_KEY environment variable"
            )
        self.api_key = api_key

        if base_url is None:
            base_url = os.environ.get("Y2_BASE_URL")
        if base_url is None:
            base_url = f"https://api.y2.dev/api/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 reports(self) -> AsyncReportsResource:
        """Intelligence report operations"""
        from .resources.reports import AsyncReportsResource

        return AsyncReportsResource(self)

    @cached_property
    def profiles(self) -> AsyncProfilesResource:
        """Subscription profile operations"""
        from .resources.profiles import AsyncProfilesResource

        return AsyncProfilesResource(self)

    @cached_property
    def news(self) -> AsyncNewsResource:
        """GloriaAI news terminal operations"""
        from .resources.news import AsyncNewsResource

        return AsyncNewsResource(self)

    @cached_property
    def webhooks(self) -> AsyncWebhooksResource:
        """Webhook configuration management (Pro feature)"""
        from .resources.webhooks import AsyncWebhooksResource

        return AsyncWebhooksResource(self)

    @cached_property
    def subscriptions(self) -> AsyncSubscriptionsResource:
        """Subscription delivery management"""
        from .resources.subscriptions import AsyncSubscriptionsResource

        return AsyncSubscriptionsResource(self)

    @cached_property
    def osint(self) -> AsyncOsintResource:
        """Situation Room OSINT intelligence operations"""
        from .resources.osint import AsyncOsintResource

        return AsyncOsintResource(self)

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

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

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

    @property
    @override
    def auth_headers(self) -> dict[str, str]:
        api_key = self.api_key
        return {"Authorization": f"Bearer {api_key}"}

    @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,
        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,
            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 Y2WithRawResponse:
    _client: Y2

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

    @cached_property
    def reports(self) -> reports.ReportsResourceWithRawResponse:
        """Intelligence report operations"""
        from .resources.reports import ReportsResourceWithRawResponse

        return ReportsResourceWithRawResponse(self._client.reports)

    @cached_property
    def profiles(self) -> profiles.ProfilesResourceWithRawResponse:
        """Subscription profile operations"""
        from .resources.profiles import ProfilesResourceWithRawResponse

        return ProfilesResourceWithRawResponse(self._client.profiles)

    @cached_property
    def news(self) -> news.NewsResourceWithRawResponse:
        """GloriaAI news terminal operations"""
        from .resources.news import NewsResourceWithRawResponse

        return NewsResourceWithRawResponse(self._client.news)

    @cached_property
    def webhooks(self) -> webhooks.WebhooksResourceWithRawResponse:
        """Webhook configuration management (Pro feature)"""
        from .resources.webhooks import WebhooksResourceWithRawResponse

        return WebhooksResourceWithRawResponse(self._client.webhooks)

    @cached_property
    def subscriptions(self) -> subscriptions.SubscriptionsResourceWithRawResponse:
        """Subscription delivery management"""
        from .resources.subscriptions import SubscriptionsResourceWithRawResponse

        return SubscriptionsResourceWithRawResponse(self._client.subscriptions)

    @cached_property
    def osint(self) -> osint.OsintResourceWithRawResponse:
        """Situation Room OSINT intelligence operations"""
        from .resources.osint import OsintResourceWithRawResponse

        return OsintResourceWithRawResponse(self._client.osint)


class AsyncY2WithRawResponse:
    _client: AsyncY2

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

    @cached_property
    def reports(self) -> reports.AsyncReportsResourceWithRawResponse:
        """Intelligence report operations"""
        from .resources.reports import AsyncReportsResourceWithRawResponse

        return AsyncReportsResourceWithRawResponse(self._client.reports)

    @cached_property
    def profiles(self) -> profiles.AsyncProfilesResourceWithRawResponse:
        """Subscription profile operations"""
        from .resources.profiles import AsyncProfilesResourceWithRawResponse

        return AsyncProfilesResourceWithRawResponse(self._client.profiles)

    @cached_property
    def news(self) -> news.AsyncNewsResourceWithRawResponse:
        """GloriaAI news terminal operations"""
        from .resources.news import AsyncNewsResourceWithRawResponse

        return AsyncNewsResourceWithRawResponse(self._client.news)

    @cached_property
    def webhooks(self) -> webhooks.AsyncWebhooksResourceWithRawResponse:
        """Webhook configuration management (Pro feature)"""
        from .resources.webhooks import AsyncWebhooksResourceWithRawResponse

        return AsyncWebhooksResourceWithRawResponse(self._client.webhooks)

    @cached_property
    def subscriptions(self) -> subscriptions.AsyncSubscriptionsResourceWithRawResponse:
        """Subscription delivery management"""
        from .resources.subscriptions import AsyncSubscriptionsResourceWithRawResponse

        return AsyncSubscriptionsResourceWithRawResponse(self._client.subscriptions)

    @cached_property
    def osint(self) -> osint.AsyncOsintResourceWithRawResponse:
        """Situation Room OSINT intelligence operations"""
        from .resources.osint import AsyncOsintResourceWithRawResponse

        return AsyncOsintResourceWithRawResponse(self._client.osint)


class Y2WithStreamedResponse:
    _client: Y2

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

    @cached_property
    def reports(self) -> reports.ReportsResourceWithStreamingResponse:
        """Intelligence report operations"""
        from .resources.reports import ReportsResourceWithStreamingResponse

        return ReportsResourceWithStreamingResponse(self._client.reports)

    @cached_property
    def profiles(self) -> profiles.ProfilesResourceWithStreamingResponse:
        """Subscription profile operations"""
        from .resources.profiles import ProfilesResourceWithStreamingResponse

        return ProfilesResourceWithStreamingResponse(self._client.profiles)

    @cached_property
    def news(self) -> news.NewsResourceWithStreamingResponse:
        """GloriaAI news terminal operations"""
        from .resources.news import NewsResourceWithStreamingResponse

        return NewsResourceWithStreamingResponse(self._client.news)

    @cached_property
    def webhooks(self) -> webhooks.WebhooksResourceWithStreamingResponse:
        """Webhook configuration management (Pro feature)"""
        from .resources.webhooks import WebhooksResourceWithStreamingResponse

        return WebhooksResourceWithStreamingResponse(self._client.webhooks)

    @cached_property
    def subscriptions(self) -> subscriptions.SubscriptionsResourceWithStreamingResponse:
        """Subscription delivery management"""
        from .resources.subscriptions import SubscriptionsResourceWithStreamingResponse

        return SubscriptionsResourceWithStreamingResponse(self._client.subscriptions)

    @cached_property
    def osint(self) -> osint.OsintResourceWithStreamingResponse:
        """Situation Room OSINT intelligence operations"""
        from .resources.osint import OsintResourceWithStreamingResponse

        return OsintResourceWithStreamingResponse(self._client.osint)


class AsyncY2WithStreamedResponse:
    _client: AsyncY2

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

    @cached_property
    def reports(self) -> reports.AsyncReportsResourceWithStreamingResponse:
        """Intelligence report operations"""
        from .resources.reports import AsyncReportsResourceWithStreamingResponse

        return AsyncReportsResourceWithStreamingResponse(self._client.reports)

    @cached_property
    def profiles(self) -> profiles.AsyncProfilesResourceWithStreamingResponse:
        """Subscription profile operations"""
        from .resources.profiles import AsyncProfilesResourceWithStreamingResponse

        return AsyncProfilesResourceWithStreamingResponse(self._client.profiles)

    @cached_property
    def news(self) -> news.AsyncNewsResourceWithStreamingResponse:
        """GloriaAI news terminal operations"""
        from .resources.news import AsyncNewsResourceWithStreamingResponse

        return AsyncNewsResourceWithStreamingResponse(self._client.news)

    @cached_property
    def webhooks(self) -> webhooks.AsyncWebhooksResourceWithStreamingResponse:
        """Webhook configuration management (Pro feature)"""
        from .resources.webhooks import AsyncWebhooksResourceWithStreamingResponse

        return AsyncWebhooksResourceWithStreamingResponse(self._client.webhooks)

    @cached_property
    def subscriptions(self) -> subscriptions.AsyncSubscriptionsResourceWithStreamingResponse:
        """Subscription delivery management"""
        from .resources.subscriptions import AsyncSubscriptionsResourceWithStreamingResponse

        return AsyncSubscriptionsResourceWithStreamingResponse(self._client.subscriptions)

    @cached_property
    def osint(self) -> osint.AsyncOsintResourceWithStreamingResponse:
        """Situation Room OSINT intelligence operations"""
        from .resources.osint import AsyncOsintResourceWithStreamingResponse

        return AsyncOsintResourceWithStreamingResponse(self._client.osint)


Client = Y2

AsyncClient = AsyncY2
