# This file was auto-generated by Fern from our API Definition.

import typing
from json.decoder import JSONDecodeError

from ..core.api_error import ApiError
from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from ..core.http_response import AsyncHttpResponse, HttpResponse
from ..core.jsonable_encoder import jsonable_encoder
from ..core.pydantic_utilities import parse_obj_as
from ..core.request_options import RequestOptions
from ..errors.unprocessable_entity_error import UnprocessableEntityError
from ..types.api_key_usage_detail import ApiKeyUsageDetail
from ..types.limit_update_response import LimitUpdateResponse
from ..types.usage_limits_response import UsageLimitsResponse

# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)


class RawAnalyticsLimitsClient:
    def __init__(self, *, client_wrapper: SyncClientWrapper):
        self._client_wrapper = client_wrapper

    def get_usage_limits(
        self,
        org_id: str,
        *,
        month: typing.Optional[int] = None,
        year: typing.Optional[int] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[UsageLimitsResponse]:
        """
        Get usage limits for organization.

        Returns comprehensive usage limits including organization-level limits,
        API-level aggregated limits, and per-API-key breakdown.

        **Query Parameters:**
        - `month` (optional): Month to query (1-12), defaults to current month
        - `year` (optional): Year to query, defaults to current year

        **Response includes:**
        - Organization-level monthly limit, usage, utilization, and status
        - API-level aggregated usage against organization limit
        - Per-API-key breakdown with individual limits and status
        - Summary statistics (total keys, keys with limits, keys exceeded)

        **Status Values:**
        - `ok`: utilization < 80%
        - `warning`: 80% <= utilization < 100%
        - `exceeded`: utilization >= 100%
        - `no_limit`: No limit configured

        **Perfect for:**
        - Budget monitoring dashboards
        - Cost control and alerting
        - API key management
        - Usage forecasting

        Parameters
        ----------
        org_id : str

        month : typing.Optional[int]
            Month (1-12)

        year : typing.Optional[int]
            Year

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[UsageLimitsResponse]
            Successful Response
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/analytics/usage/limits/{jsonable_encoder(org_id)}",
            method="GET",
            params={
                "month": month,
                "year": year,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    UsageLimitsResponse,
                    parse_obj_as(
                        type_=UsageLimitsResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def update_usage_limits(
        self,
        org_id: str,
        *,
        monthly_api_limit: typing.Optional[float] = OMIT,
        total_api_key_limit: typing.Optional[float] = OMIT,
        api_key_id: typing.Optional[str] = OMIT,
        api_key_limit: typing.Optional[float] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[LimitUpdateResponse]:
        """
        Update organization, total API key, and/or individual API key spending limits.

        Supports multiple update modes:
        1. Update organization limit only (provide `monthlyApiLimit`)
        2. Update total API key limit only (provide `totalApiKeyLimit`)
        3. Update individual API key limit only (provide `apiKeyId` and `apiKeyLimit`)
        4. Update any combination of the above limits atomically

        **Request Body:**
        - `monthlyApiLimit` (optional): Organization limit in CHF (must be > 0)
        - `totalApiKeyLimit` (optional): Total API key limit in CHF (must be > 0)
        - `apiKeyId` (optional): API key ID
        - `apiKeyLimit` (optional): Individual API key limit in CHF (must be > 0)

        **Validation:**
        - At least one field must be provided
        - All provided limits must be positive numbers (> 0)
        - If `apiKeyId` provided, `apiKeyLimit` must also be provided
        - API key must belong to the specified organization
        - Total API key limit cannot exceed organization limit

        **Cross-Limit Constraints:**
        - Total API key limit ≤ organization limit (if org limit configured)
        - Validation applies when updating either limit or both simultaneously
        - Returns 422 error if constraint violated

        **Cache Behavior:**
        - If limit is increased above current usage, exceeded cache is cleared
        - If limit is still below usage, exceeded cache is retained
        - Requests are immediately allowed/blocked based on new limits

        **Atomic Updates:**
        - When updating multiple limits, either all succeed or all fail
        - No partial updates on validation errors

        **Perfect for:**
        - Budget adjustments
        - API key provisioning
        - Cost control management
        - Emergency limit increases

        Parameters
        ----------
        org_id : str

        monthly_api_limit : typing.Optional[float]
            Organization limit in CHF (must be > 0)

        total_api_key_limit : typing.Optional[float]
            Total API key limit in CHF (must be > 0)

        api_key_id : typing.Optional[str]
            API key ID

        api_key_limit : typing.Optional[float]
            API key limit in CHF (must be > 0)

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[LimitUpdateResponse]
            Successful Response
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/analytics/usage/limits/{jsonable_encoder(org_id)}",
            method="PUT",
            json={
                "monthly_api_limit": monthly_api_limit,
                "total_api_key_limit": total_api_key_limit,
                "api_key_id": api_key_id,
                "api_key_limit": api_key_limit,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    LimitUpdateResponse,
                    parse_obj_as(
                        type_=LimitUpdateResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def get_api_key_usage(
        self,
        org_id: str,
        api_key_id: str,
        *,
        month: typing.Optional[int] = None,
        year: typing.Optional[int] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[ApiKeyUsageDetail]:
        """
        Get detailed usage for a specific API key.

        Returns comprehensive usage information for a single API key including
        total requests, cost, synapses, neurons, and limit utilization.

        **Query Parameters:**
        - `month` (optional): Month to query (1-12), defaults to current month
        - `year` (optional): Year to query, defaults to current year

        **Response includes:**
        - API key identification (ID, name, organization)
        - Usage metrics (requests, cost, synapses, neurons, average cost)
        - Limit information (monthly limit, utilization, remaining budget, status)

        **Status Values:**
        - `ok`: utilization < 80%
        - `warning`: 80% <= utilization < 100%
        - `exceeded`: utilization >= 100%
        - `no_limit`: No limit configured

        **Perfect for:**
        - API key monitoring
        - Per-key cost tracking
        - Usage analysis
        - Limit management

        Parameters
        ----------
        org_id : str

        api_key_id : str

        month : typing.Optional[int]
            Month (1-12)

        year : typing.Optional[int]
            Year

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[ApiKeyUsageDetail]
            Successful Response
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/analytics/api-keys/usage/{jsonable_encoder(org_id)}/{jsonable_encoder(api_key_id)}",
            method="GET",
            params={
                "month": month,
                "year": year,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    ApiKeyUsageDetail,
                    parse_obj_as(
                        type_=ApiKeyUsageDetail,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)


class AsyncRawAnalyticsLimitsClient:
    def __init__(self, *, client_wrapper: AsyncClientWrapper):
        self._client_wrapper = client_wrapper

    async def get_usage_limits(
        self,
        org_id: str,
        *,
        month: typing.Optional[int] = None,
        year: typing.Optional[int] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[UsageLimitsResponse]:
        """
        Get usage limits for organization.

        Returns comprehensive usage limits including organization-level limits,
        API-level aggregated limits, and per-API-key breakdown.

        **Query Parameters:**
        - `month` (optional): Month to query (1-12), defaults to current month
        - `year` (optional): Year to query, defaults to current year

        **Response includes:**
        - Organization-level monthly limit, usage, utilization, and status
        - API-level aggregated usage against organization limit
        - Per-API-key breakdown with individual limits and status
        - Summary statistics (total keys, keys with limits, keys exceeded)

        **Status Values:**
        - `ok`: utilization < 80%
        - `warning`: 80% <= utilization < 100%
        - `exceeded`: utilization >= 100%
        - `no_limit`: No limit configured

        **Perfect for:**
        - Budget monitoring dashboards
        - Cost control and alerting
        - API key management
        - Usage forecasting

        Parameters
        ----------
        org_id : str

        month : typing.Optional[int]
            Month (1-12)

        year : typing.Optional[int]
            Year

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[UsageLimitsResponse]
            Successful Response
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/analytics/usage/limits/{jsonable_encoder(org_id)}",
            method="GET",
            params={
                "month": month,
                "year": year,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    UsageLimitsResponse,
                    parse_obj_as(
                        type_=UsageLimitsResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def update_usage_limits(
        self,
        org_id: str,
        *,
        monthly_api_limit: typing.Optional[float] = OMIT,
        total_api_key_limit: typing.Optional[float] = OMIT,
        api_key_id: typing.Optional[str] = OMIT,
        api_key_limit: typing.Optional[float] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[LimitUpdateResponse]:
        """
        Update organization, total API key, and/or individual API key spending limits.

        Supports multiple update modes:
        1. Update organization limit only (provide `monthlyApiLimit`)
        2. Update total API key limit only (provide `totalApiKeyLimit`)
        3. Update individual API key limit only (provide `apiKeyId` and `apiKeyLimit`)
        4. Update any combination of the above limits atomically

        **Request Body:**
        - `monthlyApiLimit` (optional): Organization limit in CHF (must be > 0)
        - `totalApiKeyLimit` (optional): Total API key limit in CHF (must be > 0)
        - `apiKeyId` (optional): API key ID
        - `apiKeyLimit` (optional): Individual API key limit in CHF (must be > 0)

        **Validation:**
        - At least one field must be provided
        - All provided limits must be positive numbers (> 0)
        - If `apiKeyId` provided, `apiKeyLimit` must also be provided
        - API key must belong to the specified organization
        - Total API key limit cannot exceed organization limit

        **Cross-Limit Constraints:**
        - Total API key limit ≤ organization limit (if org limit configured)
        - Validation applies when updating either limit or both simultaneously
        - Returns 422 error if constraint violated

        **Cache Behavior:**
        - If limit is increased above current usage, exceeded cache is cleared
        - If limit is still below usage, exceeded cache is retained
        - Requests are immediately allowed/blocked based on new limits

        **Atomic Updates:**
        - When updating multiple limits, either all succeed or all fail
        - No partial updates on validation errors

        **Perfect for:**
        - Budget adjustments
        - API key provisioning
        - Cost control management
        - Emergency limit increases

        Parameters
        ----------
        org_id : str

        monthly_api_limit : typing.Optional[float]
            Organization limit in CHF (must be > 0)

        total_api_key_limit : typing.Optional[float]
            Total API key limit in CHF (must be > 0)

        api_key_id : typing.Optional[str]
            API key ID

        api_key_limit : typing.Optional[float]
            API key limit in CHF (must be > 0)

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[LimitUpdateResponse]
            Successful Response
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/analytics/usage/limits/{jsonable_encoder(org_id)}",
            method="PUT",
            json={
                "monthly_api_limit": monthly_api_limit,
                "total_api_key_limit": total_api_key_limit,
                "api_key_id": api_key_id,
                "api_key_limit": api_key_limit,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    LimitUpdateResponse,
                    parse_obj_as(
                        type_=LimitUpdateResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def get_api_key_usage(
        self,
        org_id: str,
        api_key_id: str,
        *,
        month: typing.Optional[int] = None,
        year: typing.Optional[int] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[ApiKeyUsageDetail]:
        """
        Get detailed usage for a specific API key.

        Returns comprehensive usage information for a single API key including
        total requests, cost, synapses, neurons, and limit utilization.

        **Query Parameters:**
        - `month` (optional): Month to query (1-12), defaults to current month
        - `year` (optional): Year to query, defaults to current year

        **Response includes:**
        - API key identification (ID, name, organization)
        - Usage metrics (requests, cost, synapses, neurons, average cost)
        - Limit information (monthly limit, utilization, remaining budget, status)

        **Status Values:**
        - `ok`: utilization < 80%
        - `warning`: 80% <= utilization < 100%
        - `exceeded`: utilization >= 100%
        - `no_limit`: No limit configured

        **Perfect for:**
        - API key monitoring
        - Per-key cost tracking
        - Usage analysis
        - Limit management

        Parameters
        ----------
        org_id : str

        api_key_id : str

        month : typing.Optional[int]
            Month (1-12)

        year : typing.Optional[int]
            Year

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[ApiKeyUsageDetail]
            Successful Response
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/analytics/api-keys/usage/{jsonable_encoder(org_id)}/{jsonable_encoder(api_key_id)}",
            method="GET",
            params={
                "month": month,
                "year": year,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    ApiKeyUsageDetail,
                    parse_obj_as(
                        type_=ApiKeyUsageDetail,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
