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

import datetime as dt
import typing
from json.decoder import JSONDecodeError

from ..commons.errors.access_denied_error import AccessDeniedError
from ..commons.errors.error import Error
from ..commons.errors.method_not_allowed_error import MethodNotAllowedError
from ..commons.errors.not_found_error import NotFoundError
from ..commons.errors.unauthorized_error import UnauthorizedError
from ..core.api_error import ApiError
from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from ..core.datetime_utils import serialize_datetime
from ..core.http_response import AsyncHttpResponse, HttpResponse
from ..core.pydantic_utilities import parse_obj_as
from ..core.request_options import RequestOptions
from .types.get_scores_v3response import GetScoresV3Response


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

    def get_many_v3(
        self,
        *,
        limit: typing.Optional[int] = None,
        cursor: typing.Optional[str] = None,
        fields: typing.Optional[str] = None,
        id: typing.Optional[str] = None,
        name: typing.Optional[str] = None,
        source: typing.Optional[str] = None,
        data_type: typing.Optional[str] = None,
        environment: typing.Optional[str] = None,
        config_id: typing.Optional[str] = None,
        queue_id: typing.Optional[str] = None,
        author_user_id: typing.Optional[str] = None,
        value: typing.Optional[str] = None,
        value_min: typing.Optional[float] = None,
        value_max: typing.Optional[float] = None,
        trace_id: typing.Optional[str] = None,
        session_id: typing.Optional[str] = None,
        observation_id: typing.Optional[str] = None,
        experiment_id: typing.Optional[str] = None,
        from_timestamp: typing.Optional[dt.datetime] = None,
        to_timestamp: typing.Optional[dt.datetime] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[GetScoresV3Response]:
        """
        Get a list of scores with a polymorphic `value` field (v3).

        The `value` field type depends on `dataType`:
        - `NUMERIC` → number
        - `BOOLEAN` → boolean
        - `CATEGORICAL`, `TEXT`, `CORRECTION` → string

        The response always includes the core fields: id, projectId, name,
        value, dataType, source, timestamp, environment, createdAt, updatedAt.

        Additional field groups can be requested via the `fields` parameter:
        - `details` — adds comment, configId, metadata
        - `subject` — adds the subject object describing the entity the score
          is attached to: kind (trace, observation, session, or experiment),
          id, and traceId for observation-level scores
        - `annotation` — adds authorUserId, queueId

        Unknown group names return HTTP 400.

        Parameters
        ----------
        limit : typing.Optional[int]
            Number of items per page. Maximum 100, default 50. Requests with a limit greater than 100 return HTTP 400.

        cursor : typing.Optional[str]
            URL-safe base64 (base64url) cursor for pagination. Use the cursor from the previous response to get the next page. Absent on the final page.

        fields : typing.Optional[str]
            Comma-separated field groups to include in addition to the always-returned core fields. Allowed: details, subject, annotation — see the endpoint description for the fields each group adds. Unknown names return HTTP 400.

        id : typing.Optional[str]
            Comma-separated list of score IDs to filter by (OR within, AND across filters).

        name : typing.Optional[str]
            Comma-separated list of score names to filter by.

        source : typing.Optional[str]
            Comma-separated list of score sources to filter by (e.g. API, ANNOTATION, EVAL). Case-insensitive — `api` and `API` are equivalent.

        data_type : typing.Optional[str]
            Comma-separated list of data types to filter by (NUMERIC, BOOLEAN, CATEGORICAL, TEXT, CORRECTION). Case-insensitive — `numeric` and `NUMERIC` are equivalent. Must be a single value when used with value, valueMin, or valueMax; otherwise the request returns HTTP 400. Must be NUMERIC when used with valueMin or valueMax.

        environment : typing.Optional[str]
            Comma-separated list of environments to filter by.

        config_id : typing.Optional[str]
            Comma-separated list of score config IDs to filter by.

        queue_id : typing.Optional[str]
            Comma-separated list of annotation queue IDs to filter by.

        author_user_id : typing.Optional[str]
            Comma-separated list of author user IDs to filter by.

        value : typing.Optional[str]
            Comma-separated list of exact values to filter by. Requires a single dataType from NUMERIC, BOOLEAN, or CATEGORICAL; any other dataType, multiple dataTypes, or omitting dataType returns HTTP 400. For BOOLEAN, each value must be "true" or "false"; for NUMERIC, each value must be a finite number. Otherwise the request returns HTTP 400.

        value_min : typing.Optional[float]
            Inclusive lower bound on the numeric value. Requires dataType=NUMERIC as a single value; otherwise the request returns HTTP 400.

        value_max : typing.Optional[float]
            Inclusive upper bound on the numeric value. Requires dataType=NUMERIC as a single value; otherwise the request returns HTTP 400.

        trace_id : typing.Optional[str]
            Comma-separated list of trace IDs to filter by. Mutually exclusive with sessionId, experimentId. May be combined with observationId to scope the observation lookup to a specific trace.

        session_id : typing.Optional[str]
            Comma-separated list of session IDs to filter by. Mutually exclusive with traceId, observationId, experimentId.

        observation_id : typing.Optional[str]
            Comma-separated list of observation IDs to filter by. Requires traceId to be specified, because observation IDs are scoped to a trace. Mutually exclusive with sessionId, experimentId. Returns HTTP 400 when used without traceId.

        experiment_id : typing.Optional[str]
            Comma-separated list of dataset run IDs (experiment IDs) to filter by. Mutually exclusive with traceId, sessionId, observationId.

        from_timestamp : typing.Optional[dt.datetime]
            Inclusive lower bound on the score timestamp.

        to_timestamp : typing.Optional[dt.datetime]
            Exclusive upper bound on the score timestamp.

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

        Returns
        -------
        HttpResponse[GetScoresV3Response]
        """
        _response = self._client_wrapper.httpx_client.request(
            "api/public/v3/scores",
            method="GET",
            params={
                "limit": limit,
                "cursor": cursor,
                "fields": fields,
                "id": id,
                "name": name,
                "source": source,
                "dataType": data_type,
                "environment": environment,
                "configId": config_id,
                "queueId": queue_id,
                "authorUserId": author_user_id,
                "value": value,
                "valueMin": value_min,
                "valueMax": value_max,
                "traceId": trace_id,
                "sessionId": session_id,
                "observationId": observation_id,
                "experimentId": experiment_id,
                "fromTimestamp": serialize_datetime(from_timestamp)
                if from_timestamp is not None
                else None,
                "toTimestamp": serialize_datetime(to_timestamp)
                if to_timestamp is not None
                else None,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    GetScoresV3Response,
                    parse_obj_as(
                        type_=GetScoresV3Response,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise Error(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 403:
                raise AccessDeniedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 405:
                raise MethodNotAllowedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    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 AsyncRawScoresV3Client:
    def __init__(self, *, client_wrapper: AsyncClientWrapper):
        self._client_wrapper = client_wrapper

    async def get_many_v3(
        self,
        *,
        limit: typing.Optional[int] = None,
        cursor: typing.Optional[str] = None,
        fields: typing.Optional[str] = None,
        id: typing.Optional[str] = None,
        name: typing.Optional[str] = None,
        source: typing.Optional[str] = None,
        data_type: typing.Optional[str] = None,
        environment: typing.Optional[str] = None,
        config_id: typing.Optional[str] = None,
        queue_id: typing.Optional[str] = None,
        author_user_id: typing.Optional[str] = None,
        value: typing.Optional[str] = None,
        value_min: typing.Optional[float] = None,
        value_max: typing.Optional[float] = None,
        trace_id: typing.Optional[str] = None,
        session_id: typing.Optional[str] = None,
        observation_id: typing.Optional[str] = None,
        experiment_id: typing.Optional[str] = None,
        from_timestamp: typing.Optional[dt.datetime] = None,
        to_timestamp: typing.Optional[dt.datetime] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[GetScoresV3Response]:
        """
        Get a list of scores with a polymorphic `value` field (v3).

        The `value` field type depends on `dataType`:
        - `NUMERIC` → number
        - `BOOLEAN` → boolean
        - `CATEGORICAL`, `TEXT`, `CORRECTION` → string

        The response always includes the core fields: id, projectId, name,
        value, dataType, source, timestamp, environment, createdAt, updatedAt.

        Additional field groups can be requested via the `fields` parameter:
        - `details` — adds comment, configId, metadata
        - `subject` — adds the subject object describing the entity the score
          is attached to: kind (trace, observation, session, or experiment),
          id, and traceId for observation-level scores
        - `annotation` — adds authorUserId, queueId

        Unknown group names return HTTP 400.

        Parameters
        ----------
        limit : typing.Optional[int]
            Number of items per page. Maximum 100, default 50. Requests with a limit greater than 100 return HTTP 400.

        cursor : typing.Optional[str]
            URL-safe base64 (base64url) cursor for pagination. Use the cursor from the previous response to get the next page. Absent on the final page.

        fields : typing.Optional[str]
            Comma-separated field groups to include in addition to the always-returned core fields. Allowed: details, subject, annotation — see the endpoint description for the fields each group adds. Unknown names return HTTP 400.

        id : typing.Optional[str]
            Comma-separated list of score IDs to filter by (OR within, AND across filters).

        name : typing.Optional[str]
            Comma-separated list of score names to filter by.

        source : typing.Optional[str]
            Comma-separated list of score sources to filter by (e.g. API, ANNOTATION, EVAL). Case-insensitive — `api` and `API` are equivalent.

        data_type : typing.Optional[str]
            Comma-separated list of data types to filter by (NUMERIC, BOOLEAN, CATEGORICAL, TEXT, CORRECTION). Case-insensitive — `numeric` and `NUMERIC` are equivalent. Must be a single value when used with value, valueMin, or valueMax; otherwise the request returns HTTP 400. Must be NUMERIC when used with valueMin or valueMax.

        environment : typing.Optional[str]
            Comma-separated list of environments to filter by.

        config_id : typing.Optional[str]
            Comma-separated list of score config IDs to filter by.

        queue_id : typing.Optional[str]
            Comma-separated list of annotation queue IDs to filter by.

        author_user_id : typing.Optional[str]
            Comma-separated list of author user IDs to filter by.

        value : typing.Optional[str]
            Comma-separated list of exact values to filter by. Requires a single dataType from NUMERIC, BOOLEAN, or CATEGORICAL; any other dataType, multiple dataTypes, or omitting dataType returns HTTP 400. For BOOLEAN, each value must be "true" or "false"; for NUMERIC, each value must be a finite number. Otherwise the request returns HTTP 400.

        value_min : typing.Optional[float]
            Inclusive lower bound on the numeric value. Requires dataType=NUMERIC as a single value; otherwise the request returns HTTP 400.

        value_max : typing.Optional[float]
            Inclusive upper bound on the numeric value. Requires dataType=NUMERIC as a single value; otherwise the request returns HTTP 400.

        trace_id : typing.Optional[str]
            Comma-separated list of trace IDs to filter by. Mutually exclusive with sessionId, experimentId. May be combined with observationId to scope the observation lookup to a specific trace.

        session_id : typing.Optional[str]
            Comma-separated list of session IDs to filter by. Mutually exclusive with traceId, observationId, experimentId.

        observation_id : typing.Optional[str]
            Comma-separated list of observation IDs to filter by. Requires traceId to be specified, because observation IDs are scoped to a trace. Mutually exclusive with sessionId, experimentId. Returns HTTP 400 when used without traceId.

        experiment_id : typing.Optional[str]
            Comma-separated list of dataset run IDs (experiment IDs) to filter by. Mutually exclusive with traceId, sessionId, observationId.

        from_timestamp : typing.Optional[dt.datetime]
            Inclusive lower bound on the score timestamp.

        to_timestamp : typing.Optional[dt.datetime]
            Exclusive upper bound on the score timestamp.

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

        Returns
        -------
        AsyncHttpResponse[GetScoresV3Response]
        """
        _response = await self._client_wrapper.httpx_client.request(
            "api/public/v3/scores",
            method="GET",
            params={
                "limit": limit,
                "cursor": cursor,
                "fields": fields,
                "id": id,
                "name": name,
                "source": source,
                "dataType": data_type,
                "environment": environment,
                "configId": config_id,
                "queueId": queue_id,
                "authorUserId": author_user_id,
                "value": value,
                "valueMin": value_min,
                "valueMax": value_max,
                "traceId": trace_id,
                "sessionId": session_id,
                "observationId": observation_id,
                "experimentId": experiment_id,
                "fromTimestamp": serialize_datetime(from_timestamp)
                if from_timestamp is not None
                else None,
                "toTimestamp": serialize_datetime(to_timestamp)
                if to_timestamp is not None
                else None,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    GetScoresV3Response,
                    parse_obj_as(
                        type_=GetScoresV3Response,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise Error(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 403:
                raise AccessDeniedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 405:
                raise MethodNotAllowedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        parse_obj_as(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    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,
        )
