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

import typing
from ...core.client_wrapper import SyncClientWrapper
from ...core.request_options import RequestOptions
from ...core.http_response import HttpResponse
from ...types.paginated_test_suite_test_case_list import PaginatedTestSuiteTestCaseList
from ...core.jsonable_encoder import jsonable_encoder
from ...core.pydantic_utilities import parse_obj_as
from json.decoder import JSONDecodeError
from ...core.api_error import ApiError
from ...types.named_test_case_variable_value_request import NamedTestCaseVariableValueRequest
from ...types.test_suite_test_case import TestSuiteTestCase
from ...core.serialization import convert_and_respect_annotation_metadata
from ...types.test_suite_test_case_bulk_operation_request import TestSuiteTestCaseBulkOperationRequest
from ...types.test_suite_test_case_bulk_result import TestSuiteTestCaseBulkResult
import json
import contextlib
from ...core.client_wrapper import AsyncClientWrapper
from ...core.http_response import AsyncHttpResponse

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


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

    def list_test_suite_test_cases(
        self,
        id: str,
        *,
        limit: typing.Optional[int] = None,
        offset: typing.Optional[int] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[PaginatedTestSuiteTestCaseList]:
        """
        List the Test Cases associated with a Test Suite

        Parameters
        ----------
        id : str
            Either the Test Suites' ID or its unique name

        limit : typing.Optional[int]
            Number of results to return per page.

        offset : typing.Optional[int]
            The initial index from which to return the results.

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

        Returns
        -------
        HttpResponse[PaginatedTestSuiteTestCaseList]

        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/test-suites/{jsonable_encoder(id)}/test-cases",
            base_url=self._client_wrapper.get_environment().default,
            method="GET",
            params={
                "limit": limit,
                "offset": offset,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    PaginatedTestSuiteTestCaseList,
                    parse_obj_as(
                        type_=PaginatedTestSuiteTestCaseList,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def upsert_test_suite_test_case(
        self,
        id_: str,
        *,
        input_values: typing.Sequence[NamedTestCaseVariableValueRequest],
        evaluation_values: typing.Sequence[NamedTestCaseVariableValueRequest],
        id: typing.Optional[str] = OMIT,
        external_id: typing.Optional[str] = OMIT,
        label: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[TestSuiteTestCase]:
        """
        Upserts a new test case for a test suite, keying off of the optionally provided test case id.

        If an id is provided and has a match, the test case will be updated. If no id is provided or no match
        is found, a new test case will be appended to the end.

        Note that a full replacement of the test case is performed, so any fields not provided will be removed
        or overwritten with default values.

        Parameters
        ----------
        id_ : str
            Either the Test Suites' ID or its unique name

        input_values : typing.Sequence[NamedTestCaseVariableValueRequest]
            Values for each of the Test Case's input variables

        evaluation_values : typing.Sequence[NamedTestCaseVariableValueRequest]
            Values for each of the Test Case's evaluation variables

        id : typing.Optional[str]
            The Vellum-generated ID of an existing Test Case whose data you'd like to replace. If specified and no Test Case exists with this ID, a 404 will be returned.

        external_id : typing.Optional[str]
            An ID external to Vellum that uniquely identifies the Test Case that you'd like to create/update. If there's a match on a Test Case that was previously created with the same external_id, it will be updated. Otherwise, a new Test Case will be created with this value as its external_id. If no external_id is specified, then a new Test Case will always be created.

        label : typing.Optional[str]
            A human-readable label used to convey the intention of this Test Case

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

        Returns
        -------
        HttpResponse[TestSuiteTestCase]

        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/test-suites/{jsonable_encoder(id_)}/test-cases",
            base_url=self._client_wrapper.get_environment().default,
            method="POST",
            json={
                "id": id,
                "external_id": external_id,
                "label": label,
                "input_values": convert_and_respect_annotation_metadata(
                    object_=input_values,
                    annotation=typing.Sequence[NamedTestCaseVariableValueRequest],
                    direction="write",
                ),
                "evaluation_values": convert_and_respect_annotation_metadata(
                    object_=evaluation_values,
                    annotation=typing.Sequence[NamedTestCaseVariableValueRequest],
                    direction="write",
                ),
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TestSuiteTestCase,
                    parse_obj_as(
                        type_=TestSuiteTestCase,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    @contextlib.contextmanager
    def test_suite_test_cases_bulk(
        self,
        id: str,
        *,
        request: typing.Sequence[TestSuiteTestCaseBulkOperationRequest],
        request_options: typing.Optional[RequestOptions] = None,
    ) -> typing.Iterator[HttpResponse[typing.Iterator[typing.List[TestSuiteTestCaseBulkResult]]]]:
        """
        Created, replace, and delete Test Cases within the specified Test Suite in bulk

        Parameters
        ----------
        id : str
            Either the Test Suites' ID or its unique name

        request : typing.Sequence[TestSuiteTestCaseBulkOperationRequest]

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

        Yields
        ------
        typing.Iterator[HttpResponse[typing.Iterator[typing.List[TestSuiteTestCaseBulkResult]]]]

        """
        with self._client_wrapper.httpx_client.stream(
            f"v1/test-suites/{jsonable_encoder(id)}/test-cases-bulk",
            base_url=self._client_wrapper.get_environment().default,
            method="POST",
            json=convert_and_respect_annotation_metadata(
                object_=request, annotation=typing.Sequence[TestSuiteTestCaseBulkOperationRequest], direction="write"
            ),
            request_options=request_options,
            omit=OMIT,
        ) as _response:

            def stream() -> HttpResponse[typing.Iterator[typing.List[TestSuiteTestCaseBulkResult]]]:
                try:
                    if 200 <= _response.status_code < 300:

                        def _iter():
                            for _text in _response.iter_lines():
                                try:
                                    if len(_text) == 0:
                                        continue
                                    yield typing.cast(
                                        typing.List[TestSuiteTestCaseBulkResult],
                                        parse_obj_as(
                                            type_=typing.List[TestSuiteTestCaseBulkResult],  # type: ignore
                                            object_=json.loads(_text),
                                        ),
                                    )
                                except Exception:
                                    pass
                            return

                        return HttpResponse(response=_response, data=_iter())
                    _response.read()
                    _response_json = _response.json()
                except JSONDecodeError:
                    raise ApiError(status_code=_response.status_code, body=_response.text)
                raise ApiError(status_code=_response.status_code, body=_response_json)

            yield stream()

    def delete_test_suite_test_case(
        self, id: str, test_case_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[None]:
        """
        Deletes an existing test case for a test suite, keying off of the test case id.

        Parameters
        ----------
        id : str
            Either the Test Suites' ID or its unique name

        test_case_id : str
            An id identifying the test case that you'd like to delete

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

        Returns
        -------
        HttpResponse[None]
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/test-suites/{jsonable_encoder(id)}/test-cases/{jsonable_encoder(test_case_id)}",
            base_url=self._client_wrapper.get_environment().default,
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return HttpResponse(response=_response, data=None)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)


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

    async def list_test_suite_test_cases(
        self,
        id: str,
        *,
        limit: typing.Optional[int] = None,
        offset: typing.Optional[int] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[PaginatedTestSuiteTestCaseList]:
        """
        List the Test Cases associated with a Test Suite

        Parameters
        ----------
        id : str
            Either the Test Suites' ID or its unique name

        limit : typing.Optional[int]
            Number of results to return per page.

        offset : typing.Optional[int]
            The initial index from which to return the results.

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

        Returns
        -------
        AsyncHttpResponse[PaginatedTestSuiteTestCaseList]

        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/test-suites/{jsonable_encoder(id)}/test-cases",
            base_url=self._client_wrapper.get_environment().default,
            method="GET",
            params={
                "limit": limit,
                "offset": offset,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    PaginatedTestSuiteTestCaseList,
                    parse_obj_as(
                        type_=PaginatedTestSuiteTestCaseList,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def upsert_test_suite_test_case(
        self,
        id_: str,
        *,
        input_values: typing.Sequence[NamedTestCaseVariableValueRequest],
        evaluation_values: typing.Sequence[NamedTestCaseVariableValueRequest],
        id: typing.Optional[str] = OMIT,
        external_id: typing.Optional[str] = OMIT,
        label: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[TestSuiteTestCase]:
        """
        Upserts a new test case for a test suite, keying off of the optionally provided test case id.

        If an id is provided and has a match, the test case will be updated. If no id is provided or no match
        is found, a new test case will be appended to the end.

        Note that a full replacement of the test case is performed, so any fields not provided will be removed
        or overwritten with default values.

        Parameters
        ----------
        id_ : str
            Either the Test Suites' ID or its unique name

        input_values : typing.Sequence[NamedTestCaseVariableValueRequest]
            Values for each of the Test Case's input variables

        evaluation_values : typing.Sequence[NamedTestCaseVariableValueRequest]
            Values for each of the Test Case's evaluation variables

        id : typing.Optional[str]
            The Vellum-generated ID of an existing Test Case whose data you'd like to replace. If specified and no Test Case exists with this ID, a 404 will be returned.

        external_id : typing.Optional[str]
            An ID external to Vellum that uniquely identifies the Test Case that you'd like to create/update. If there's a match on a Test Case that was previously created with the same external_id, it will be updated. Otherwise, a new Test Case will be created with this value as its external_id. If no external_id is specified, then a new Test Case will always be created.

        label : typing.Optional[str]
            A human-readable label used to convey the intention of this Test Case

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

        Returns
        -------
        AsyncHttpResponse[TestSuiteTestCase]

        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/test-suites/{jsonable_encoder(id_)}/test-cases",
            base_url=self._client_wrapper.get_environment().default,
            method="POST",
            json={
                "id": id,
                "external_id": external_id,
                "label": label,
                "input_values": convert_and_respect_annotation_metadata(
                    object_=input_values,
                    annotation=typing.Sequence[NamedTestCaseVariableValueRequest],
                    direction="write",
                ),
                "evaluation_values": convert_and_respect_annotation_metadata(
                    object_=evaluation_values,
                    annotation=typing.Sequence[NamedTestCaseVariableValueRequest],
                    direction="write",
                ),
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TestSuiteTestCase,
                    parse_obj_as(
                        type_=TestSuiteTestCase,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    @contextlib.asynccontextmanager
    async def test_suite_test_cases_bulk(
        self,
        id: str,
        *,
        request: typing.Sequence[TestSuiteTestCaseBulkOperationRequest],
        request_options: typing.Optional[RequestOptions] = None,
    ) -> typing.AsyncIterator[AsyncHttpResponse[typing.AsyncIterator[typing.List[TestSuiteTestCaseBulkResult]]]]:
        """
        Created, replace, and delete Test Cases within the specified Test Suite in bulk

        Parameters
        ----------
        id : str
            Either the Test Suites' ID or its unique name

        request : typing.Sequence[TestSuiteTestCaseBulkOperationRequest]

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

        Yields
        ------
        typing.AsyncIterator[AsyncHttpResponse[typing.AsyncIterator[typing.List[TestSuiteTestCaseBulkResult]]]]

        """
        async with self._client_wrapper.httpx_client.stream(
            f"v1/test-suites/{jsonable_encoder(id)}/test-cases-bulk",
            base_url=self._client_wrapper.get_environment().default,
            method="POST",
            json=convert_and_respect_annotation_metadata(
                object_=request, annotation=typing.Sequence[TestSuiteTestCaseBulkOperationRequest], direction="write"
            ),
            request_options=request_options,
            omit=OMIT,
        ) as _response:

            async def stream() -> AsyncHttpResponse[typing.AsyncIterator[typing.List[TestSuiteTestCaseBulkResult]]]:
                try:
                    if 200 <= _response.status_code < 300:

                        async def _iter():
                            async for _text in _response.aiter_lines():
                                try:
                                    if len(_text) == 0:
                                        continue
                                    yield typing.cast(
                                        typing.List[TestSuiteTestCaseBulkResult],
                                        parse_obj_as(
                                            type_=typing.List[TestSuiteTestCaseBulkResult],  # type: ignore
                                            object_=json.loads(_text),
                                        ),
                                    )
                                except Exception:
                                    pass
                            return

                        return AsyncHttpResponse(response=_response, data=_iter())
                    await _response.aread()
                    _response_json = _response.json()
                except JSONDecodeError:
                    raise ApiError(status_code=_response.status_code, body=_response.text)
                raise ApiError(status_code=_response.status_code, body=_response_json)

            yield await stream()

    async def delete_test_suite_test_case(
        self, id: str, test_case_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[None]:
        """
        Deletes an existing test case for a test suite, keying off of the test case id.

        Parameters
        ----------
        id : str
            Either the Test Suites' ID or its unique name

        test_case_id : str
            An id identifying the test case that you'd like to delete

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

        Returns
        -------
        AsyncHttpResponse[None]
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/test-suites/{jsonable_encoder(id)}/test-cases/{jsonable_encoder(test_case_id)}",
            base_url=self._client_wrapper.get_environment().default,
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return AsyncHttpResponse(response=_response, data=None)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)
